#include "tree.h"
#include "log.h"
#include "private.h"
+#include "base64.h"
static int __nvme_open(const char *name)
{
}
static int gen_tls_identity(const char *hostnqn, const char *subsysnqn,
- int hmac, char *identity,
+ int version, int hmac, char *identity,
unsigned char *retained, size_t key_len)
{
+ if (version != 0) {
+ nvme_msg(NULL, LOG_ERR, "NVMe TLS 2.0 is not supported; "
+ "recompile with OpenSSL support.\n");
+ errno = NOTSUP;
+ return -1;
+ }
sprintf(identity, "NVMe0R%02d %s %s",
- version, hmac, hostnqn, subsysnqn);
+ hmac, hostnqn, subsysnqn);
return strlen(identity);
}
}
static int gen_tls_identity(const char *hostnqn, const char *subsysnqn,
- int hmac, char *identity,
+ int version, int hmac, char *identity,
unsigned char *retained, size_t key_len)
{
- sprintf(identity, "NVMe0R%02d %s %s",
- hmac, hostnqn, subsysnqn);
- return strlen(identity);
+ static const char hmac_seed[] = "NVMe-over-Fabrics";
+ size_t hmac_len;
+ const EVP_MD *md = select_hmac(hmac, &hmac_len);
+ HMAC_CTX *hmac_ctx;
+ unsigned char *psk_ctx;
+ char *enc_ctx;
+ size_t len = -1;
+
+ 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;
+ return -1;
+ }
+ if (!md) {
+ errno = EINVAL;
+ goto out_free_hmac;
+ }
+
+ psk_ctx = malloc(key_len);
+ if (!psk_ctx) {
+ errno = ENOMEM;
+ goto out_free_hmac;
+ }
+ if (!HMAC_Init_ex(hmac_ctx, retained, key_len, md, NULL)) {
+ errno = ENOMEM;
+ goto out_free_psk;
+ }
+ if (!HMAC_Update(hmac_ctx, (unsigned char *)hostnqn,
+ strlen(hostnqn))) {
+ errno = ENOKEY;
+ goto out_free_psk;
+ }
+ if (!HMAC_Update(hmac_ctx, (unsigned char *)" ", 1)) {
+ errno = ENOKEY;
+ goto out_free_psk;
+ }
+ if (!HMAC_Update(hmac_ctx, (unsigned char *)subsysnqn,
+ strlen(subsysnqn))) {
+ errno = ENOKEY;
+ goto out_free_psk;
+ }
+ if (!HMAC_Update(hmac_ctx, (unsigned char *)" ", 1)) {
+ errno = ENOKEY;
+ goto out_free_psk;
+ }
+ if (!HMAC_Update(hmac_ctx, (unsigned char *)hmac_seed,
+ strlen(hmac_seed))) {
+ errno = ENOKEY;
+ goto out_free_psk;
+ }
+ if (!HMAC_Final(hmac_ctx, psk_ctx, (unsigned int *)&key_len)) {
+ errno = ENOKEY;
+ goto out_free_psk;
+ }
+ enc_ctx = malloc(key_len * 2);
+ memset(enc_ctx, 0, key_len * 2);
+ len = base64_encode(psk_ctx, key_len, enc_ctx);
+ if (len < 0) {
+ errno = ENOKEY;
+ goto out_free_enc;
+ }
+ sprintf(identity, "NVMe%01dR%02d %s %s %s",
+ version, hmac, hostnqn, subsysnqn, enc_ctx);
+ len = strlen(identity);
+out_free_enc:
+ free(enc_ctx);
+out_free_psk:
+ free(psk_ctx);
+out_free_hmac:
+ HMAC_CTX_free(hmac_ctx);
+ return len;
}
#endif /* !CONFIG_OPENSSL_1 */
}
static int gen_tls_identity(const char *hostnqn, const char *subsysnqn,
- int hmac, char *identity,
+ int version, int hmac, char *identity,
unsigned char *retained, size_t key_len)
{
- sprintf(identity, "NVMe0R%02d %s %s",
- version, hmac, hostnqn, subsysnqn);
- return strlen(identity);
+ static const char hmac_seed[] = "NVMe-over-Fabrics";
+ size_t hmac_len;
+ OSSL_PARAM params[2], *p = params;
+ OSSL_LIB_CTX *lib_ctx;
+ EVP_MAC_CTX *mac_ctx = NULL;
+ EVP_MAC *mac = NULL;
+ char *progq = NULL;
+ char *digest = NULL;
+ unsigned char *psk_ctx;
+ char *enc_ctx;
+ size_t len = -1;
+
+ 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;
+ return -1;
+ }
+ mac = EVP_MAC_fetch(lib_ctx, OSSL_MAC_NAME_HMAC, progq);
+ if (!mac) {
+ errno = ENOMEM;
+ goto out_free_ossl;
+ }
+
+ mac_ctx = EVP_MAC_CTX_new(mac);
+ if (!mac_ctx) {
+ errno = ENOMEM;
+ goto out_free_mac;
+ }
+ switch (hmac) {
+ case NVME_HMAC_ALG_SHA2_256:
+ digest = OSSL_DIGEST_NAME_SHA2_256;
+ break;
+ case NVME_HMAC_ALG_SHA2_384:
+ digest = OSSL_DIGEST_NAME_SHA2_384;
+ break;
+ default:
+ errno = EINVAL;
+ break;
+ }
+ if (!digest)
+ goto out_free_ctx;
+ *p++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
+ digest, 0);
+ *p = OSSL_PARAM_construct_end();
+
+ psk_ctx = malloc(key_len);
+ if (!psk_ctx) {
+ errno = ENOMEM;
+ goto out_free_ctx;
+ }
+
+ if (!EVP_MAC_init(mac_ctx, retained, key_len, params)) {
+ errno = ENOKEY;
+ goto out_free_psk;
+ }
+ if (!EVP_MAC_update(mac_ctx, (unsigned char *)hostnqn,
+ strlen(hostnqn))) {
+ errno = ENOKEY;
+ goto out_free_psk;
+ }
+ if (!EVP_MAC_update(mac_ctx, (unsigned char *)" ", 1)) {
+ errno = ENOKEY;
+ goto out_free_psk;
+ }
+ if (!EVP_MAC_update(mac_ctx, (unsigned char *)subsysnqn,
+ strlen(subsysnqn))) {
+ errno = ENOKEY;
+ goto out_free_psk;
+ }
+ if (!EVP_MAC_update(mac_ctx, (unsigned char *)" ", 1)) {
+ errno = ENOKEY;
+ goto out_free_psk;
+ }
+ if (!EVP_MAC_update(mac_ctx, (unsigned char *)hmac_seed,
+ strlen(hmac_seed))) {
+ errno = ENOKEY;
+ goto out_free_psk;
+ }
+ if (!EVP_MAC_final(mac_ctx, psk_ctx, &hmac_len, key_len)) {
+ errno = ENOKEY;
+ goto out_free_psk;
+ }
+ if (hmac_len > key_len) {
+ errno = EMSGSIZE;
+ goto out_free_psk;
+ }
+ enc_ctx = malloc(hmac_len * 2);
+ memset(enc_ctx, 0, hmac_len * 2);
+ len = base64_encode(psk_ctx, hmac_len, enc_ctx);
+ if (len < 0) {
+ errno = ENOKEY;
+ goto out_free_enc;
+ }
+ sprintf(identity, "NVMe%01dR%02d %s %s %s",
+ version, hmac, hostnqn, subsysnqn, enc_ctx);
+ len = strlen(identity);
+out_free_enc:
+ free(enc_ctx);
+out_free_psk:
+ free(psk_ctx);
+out_free_ctx:
+ EVP_MAC_CTX_free(mac_ctx);
+out_free_mac:
+ EVP_MAC_free(mac);
+out_free_ossl:
+ OSSL_LIB_CTX_free(lib_ctx);
+
+ return len;
}
#endif /* !CONFIG_OPENSSL_3 */
#ifdef CONFIG_KEYUTILS
static int derive_nvme_keys(const char *hostnqn, const char *subsysnqn,
- char *identity,
+ char *identity, int version,
int hmac, unsigned char *configured,
unsigned char *psk, int key_len)
{
ret = derive_retained_key(hmac, hostnqn, configured, retained, key_len);
if (ret < 0)
goto out;
- ret = gen_tls_identity(hostnqn, subsysnqn, hmac,
+ ret = gen_tls_identity(hostnqn, subsysnqn, version, hmac,
identity, retained, key_len);
if (ret < 0)
goto out;
return ret;
}
+static size_t nvme_identity_len(int hmac, int version, const char *hostnqn,
+ const char *subsysnqn)
+{
+ size_t len;
+
+ len = strlen(hostnqn) + strlen(subsysnqn) + 12;
+ if (version == 1) {
+ len += 66;
+ if (hmac == NVME_HMAC_ALG_SHA2_384)
+ len += 32;
+ } else if (version > 1) {
+ errno = EINVAL;
+ return -1;
+ }
+ return len;
+}
+
long nvme_lookup_keyring(const char *keyring)
{
key_serial_t keyring_id;
return 0;
}
-long nvme_insert_tls_key(const char *keyring, const char *key_type,
- const char *hostnqn, const char *subsysnqn, int hmac,
- unsigned char *configured_key, int key_len)
+long nvme_insert_tls_key_versioned(const char *keyring, const char *key_type,
+ const char *hostnqn, const char *subsysnqn,
+ int version, int hmac,
+ unsigned char *configured_key, int key_len)
{
key_serial_t keyring_id, key = 0;
char *identity;
if (keyring_id == 0)
return -1;
- identity_len = strlen(hostnqn) + strlen(subsysnqn) + 12;
+ identity_len = nvme_identity_len(hmac, version, hostnqn, subsysnqn);
+ if (identity_len < 0)
+ return -1;
+
identity = malloc(identity_len);
if (!identity) {
errno = ENOMEM;
goto out_free_identity;
}
memset(psk, 0, key_len);
- ret = derive_nvme_keys(hostnqn, subsysnqn, identity, hmac,
+ ret = derive_nvme_keys(hostnqn, subsysnqn, identity, version, hmac,
configured_key, psk, key_len);
if (ret != key_len)
goto out_free_psk;
return -1;
}
-long nvme_insert_tls_key(const char *keyring, const char *key_type,
- const char *hostnqn, const char *subsysnqn, int hmac,
- unsigned char *configured_key, int key_len)
+long nvme_insert_tls_key_versioned(const char *keyring, const char *key_type,
+ const char *hostnqn, const char *subsysnqn,
+ int version, int hmac,
+ unsigned char *configured_key, int key_len)
{
nvme_msg(NULL, LOG_ERR, "key operations not supported; "
"recompile with keyutils support.\n");
return -1;
}
#endif
+
+long nvme_insert_tls_key(const char *keyring, const char *key_type,
+ const char *hostnqn, const char *subsysnqn, int hmac,
+ unsigned char *configured_key, int key_len)
+{
+ return nvme_insert_tls_key_versioned(keyring, key_type,
+ hostnqn, subsysnqn, 0, hmac,
+ configured_key, key_len);
+}