[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[RFC PATCH] crypto/secret: support fetching secrets from Linux keyring
From: |
Alexey Krasikov |
Subject: |
[RFC PATCH] crypto/secret: support fetching secrets from Linux keyring |
Date: |
Sat, 28 Mar 2020 14:40:14 +0300 |
Add the ability for the secret object to obtain secret data from the
Linux in-kernel key managment and retention facility, as an extra option
to the existing ones: reading from a file or passing directly as a
string.
The secret is identified by the key serial number. The upper layers
need to instantiate the key and make sure the QEMU process has access
rights to read it.
Signed-off-by: Alexey Krasikov <address@hidden>
---
crypto/secret.c | 88 +++++++++++++++++++++++++++++++++++++++--
include/crypto/secret.h | 3 ++
2 files changed, 88 insertions(+), 3 deletions(-)
diff --git a/crypto/secret.c b/crypto/secret.c
index 1cf0ad0ce8..2e8be6241c 100644
--- a/crypto/secret.c
+++ b/crypto/secret.c
@@ -19,6 +19,8 @@
*/
#include "qemu/osdep.h"
+#include <asm/unistd.h>
+#include <linux/keyctl.h>
#include "crypto/secret.h"
#include "crypto/cipher.h"
#include "qapi/error.h"
@@ -28,6 +30,40 @@
#include "trace.h"
+static inline
+long keyctl_read(key_serial_t key, uint8_t *buffer, size_t buflen)
+{
+#ifdef __NR_keyctl
+ return syscall(__NR_keyctl, KEYCTL_READ, key, buffer, buflen, 0);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+static
+long keyctl_read_alloc(key_serial_t key, uint8_t **buffer)
+{
+ uint8_t *loc_buf;
+ long retcode = keyctl_read(key, NULL, 0);
+ if (retcode < 0) {
+ return retcode;
+ }
+ loc_buf = g_malloc(retcode + 1);
+ retcode = keyctl_read(key, loc_buf, retcode + 1);
+ /*
+ * We don't have key operations locks between syscalls.
+ * For example, the key could have been removed or expired.
+ */
+ if (retcode >= 0) {
+ loc_buf[retcode] = '\0';
+ *buffer = loc_buf;
+ } else {
+ g_free(loc_buf);
+ }
+ return retcode;
+}
+
static void
qcrypto_secret_load_data(QCryptoSecret *secret,
uint8_t **output,
@@ -41,10 +77,28 @@ qcrypto_secret_load_data(QCryptoSecret *secret,
*output = NULL;
*outputlen = 0;
- if (secret->file) {
+ if (secret->syskey) {
+ uint8_t *buffer = NULL;
+ long retcode;
+ if (secret->data || secret->file) {
+ error_setg(errp,
+ "'syskey', 'file' and 'data' are mutually exclusive");
+ return;
+ }
+ retcode = keyctl_read_alloc(secret->syskey, &buffer);
+ if (retcode < 0) {
+ error_setg_errno(errp, errno,
+ "Unable to read serial key %08x",
+ secret->syskey);
+ return;
+ } else {
+ *outputlen = retcode;
+ *output = buffer;
+ }
+ } else if (secret->file) {
if (secret->data) {
error_setg(errp,
- "'file' and 'data' are mutually exclusive");
+ "'syskey', 'file' and 'data' are mutually exclusive");
return;
}
if (!g_file_get_contents(secret->file, &data, &length, &gerr)) {
@@ -60,7 +114,8 @@ qcrypto_secret_load_data(QCryptoSecret *secret,
*outputlen = strlen(secret->data);
*output = (uint8_t *)g_strdup(secret->data);
} else {
- error_setg(errp, "Either 'file' or 'data' must be provided");
+ error_setg(errp,
+ "Either 'syskey' or 'file' or 'data' must be provided");
}
}
@@ -298,6 +353,29 @@ qcrypto_secret_prop_get_file(Object *obj,
}
+static void
+qcrypto_secret_prop_set_syskey(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ QCryptoSecret *secret = QCRYPTO_SECRET(obj);
+ int32_t value;
+ visit_type_int32(v, name, &value, errp);
+ secret->syskey = value;
+}
+
+
+static void
+qcrypto_secret_prop_get_syskey(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ QCryptoSecret *secret = QCRYPTO_SECRET(obj);
+ int32_t value = secret->syskey;
+ visit_type_int32(v, name, &value, errp);
+}
+
+
static void
qcrypto_secret_prop_set_iv(Object *obj,
const char *value,
@@ -384,6 +462,10 @@ qcrypto_secret_class_init(ObjectClass *oc, void *data)
qcrypto_secret_prop_get_file,
qcrypto_secret_prop_set_file,
NULL);
+ object_class_property_add(oc, "syskey", "key_serial_t",
+ qcrypto_secret_prop_get_syskey,
+ qcrypto_secret_prop_set_syskey,
+ NULL, NULL, NULL);
object_class_property_add_str(oc, "keyid",
qcrypto_secret_prop_get_keyid,
qcrypto_secret_prop_set_keyid,
diff --git a/include/crypto/secret.h b/include/crypto/secret.h
index 5e07e29bae..9d350e35ed 100644
--- a/include/crypto/secret.h
+++ b/include/crypto/secret.h
@@ -31,6 +31,8 @@
typedef struct QCryptoSecret QCryptoSecret;
typedef struct QCryptoSecretClass QCryptoSecretClass;
+typedef int32_t key_serial_t;
+
/**
* QCryptoSecret:
*
@@ -125,6 +127,7 @@ struct QCryptoSecret {
QCryptoSecretFormat format;
char *data;
char *file;
+ key_serial_t syskey;
char *keyid;
char *iv;
};
--
2.17.1
- [RFC PATCH] crypto/secret: support fetching secrets from Linux keyring,
Alexey Krasikov <=