Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Persistent TLS keys #783

Closed
wants to merge 10 commits into from
6 changes: 6 additions & 0 deletions src/libnvme.map
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
LIBNVME_1_9 {
global:
nvme_read_key;
nvme_export_tls_key;
};

LIBNVME_1_8 {
global:
nvme_uuid_find;
Expand Down
3 changes: 2 additions & 1 deletion src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ sources = [
'nvme/log.c',
'nvme/tree.c',
'nvme/util.c',
'nvme/base64.c'
'nvme/base64.c',
'nvme/crc32.c'
]

mi_sources = [
Expand Down
100 changes: 100 additions & 0 deletions src/nvme/crc32.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// SPDX-License-Identifier: GPL-2.0-or-later
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The library is LGPL 2.1. So this is not compatible.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sadly, Rustys code is for crc32c (not crc32), and the crc source code from ccan also has GPLv2. So ccan doesn't help. The second implementation should be fine, though.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But ever so slightly complicated to use. Switching to the freebsd implementation, which actually has a copy with a permissible license.


/*
* Copyright (C) 2002 Red Hat, Inc.
* This file is part of elfutils.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of either
*
* * the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at
* your option) any later version
*
* or
*
* * the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at
* your option) any later version
*
* or both in parallel, as here.
*
* elfutils is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received copies of the GNU General Public License and
* the GNU Lesser General Public License along with this program. If
* not, see <http://www.gnu.org/licenses/>.
*/

/* https://sourceware.org/git/?p=elfutils.git;a=blob;f=lib/crc32.c;hb=575198c29a427392823cc8f2400579a23d06a875 */

#include "crc32.h"

/* Table computed with Mark Adler's makecrc.c utility. */
static const uint32_t crc32_table[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
0x2d02ef8d
};

uint32_t crc32(uint32_t crc, unsigned char *buf, size_t len)
{
unsigned char *end;

crc = ~crc;
for (end = buf + len; buf < end; ++buf)
crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
return ~crc;
}
11 changes: 11 additions & 0 deletions src/nvme/crc32.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again this license doesn't work for the library.


#ifndef crc32_H
#define crc32_H

#include <stdint.h>
#include <stddef.h>

uint32_t crc32(uint32_t crc, unsigned char *buf, size_t len);

#endif
76 changes: 76 additions & 0 deletions src/nvme/linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include "log.h"
#include "private.h"
#include "base64.h"
#include "crc32.h"

static int __nvme_open(const char *name)
{
Expand Down Expand Up @@ -1193,6 +1194,37 @@ int nvme_set_keyring(long key_id)
return 0;
}

unsigned char *nvme_read_key(const char *keyring, long key_id, int *len)
{
long keyring_id;
void *buffer;
int ret;

keyring_id = nvme_lookup_keyring(keyring);
if (!keyring_id) {
nvme_msg(NULL, LOG_ERR, "Failed to lookup keyring '%s'\n",
keyring);
errno = ENOKEY;
return NULL;
}
ret = nvme_set_keyring(keyring_id);
if (ret < 0) {
nvme_msg(NULL, LOG_ERR,
"Failed to link keyring '%s' (%lx) error %d\n",
keyring, keyring_id, errno);
return NULL;
hreinecke marked this conversation as resolved.
Show resolved Hide resolved
}
ret = keyctl_read_alloc(key_id, &buffer);
if (ret < 0) {
nvme_msg(NULL, LOG_ERR, "Failed to read key %08lx, error %d\n",
key_id, errno);
buffer = NULL;
} else
*len = ret;

return buffer;
}

long nvme_insert_tls_key_versioned(const char *keyring, const char *key_type,
const char *hostnqn, const char *subsysnqn,
int version, int hmac,
Expand Down Expand Up @@ -1275,6 +1307,12 @@ int nvme_set_keyring(long key_id)
return -1;
}

unsigned char *nvme_read_key(const char *keyring, long key_id, int *len)
{
errno = ENOTSUP;
return NULL;
}

long nvme_insert_tls_key_versioned(const char *keyring, const char *key_type,
const char *hostnqn, const char *subsysnqn,
int version, int hmac,
Expand All @@ -1295,3 +1333,41 @@ long nvme_insert_tls_key(const char *keyring, const char *key_type,
hostnqn, subsysnqn, 0, hmac,
configured_key, key_len);
}

char *nvme_export_tls_key(const unsigned char *key_data, int key_len)
{
unsigned char raw_secret[52];
char *encoded_key;
unsigned int raw_len, encoded_len, len;
unsigned long crc = crc32(0L, NULL, 0);

if (key_len == 32) {
raw_len = 32;
} else if (key_len == 48) {
raw_len = 48;
} else {
errno = EINVAL;
return NULL;
}

memcpy(raw_secret, key_data, raw_len);
crc = crc32(crc, raw_secret, raw_len);
raw_secret[raw_len++] = crc & 0xff;
raw_secret[raw_len++] = (crc >> 8) & 0xff;
raw_secret[raw_len++] = (crc >> 16) & 0xff;
raw_secret[raw_len++] = (crc >> 24) & 0xff;

encoded_len = (raw_len * 2) + 20;
encoded_key = malloc(encoded_len);
if (!encoded_key) {
errno = ENOMEM;
return NULL;
}
memset(encoded_key, 0, encoded_len);
len = sprintf(encoded_key, "NVMeTLSkey-1:%02x:",
key_len == 32 ? 1 : 2);
base64_encode(raw_secret, raw_len, encoded_key + len);
strcat(encoded_key, ":");

return encoded_key;
}
29 changes: 29 additions & 0 deletions src/nvme/linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,22 @@ char *nvme_describe_key_serial(long key_id);
*/
long nvme_lookup_key(const char *type, const char *identity);

/**
* nvme_read_key() - Read key raw data
* @keyring: Name of the keyring holding %key_id
* @key_id: Key id
* @len: Length of the returned data
*
* Links @keyring into the session keyring and reads the
* payload of the key specified by @key_id.
* @len holds the size of the returned buffer.
* If @keyring is NULL the default keyring '.nvme' is used.
*
* Return: Pointer to the payload on success,
* or NULL with errno set otherwise.
*/
unsigned char *nvme_read_key(const char *keyring, long key_id, int *len);

/**
* nvme_set_keyring() - Link keyring for lookup
* @keyring_id: Keyring id
Expand Down Expand Up @@ -335,4 +351,17 @@ char *nvme_generate_tls_key_identity(const char *hostnqn, const char *subsysnqn,
int version, int hmac,
unsigned char *configured_key, int key_len);

/**
* nvme_export_tls_key() - Export a TLS key
* @key_data: Raw data of the key
* @key_len: Length of @key_data
*
* Returns @key_data in the PSK Interchange format as defined in section
* 3.6.1.5 of the NVMe TCP Transport specification.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and NULL with errno set in failure case.

*
* Return: The string containing the TLS identity. It is the responsibility
* of the caller to free the returned string.
*/
char *nvme_export_tls_key(const unsigned char *key_data, int key_len);

#endif /* _LIBNVME_LINUX_H */