diff mbox series

[RFC,03/10] KEYS: asymmetric: Introduce a parser for user asymmetric keys and sigs

Message ID 20230706144225.1046544-4-roberto.sassu@huaweicloud.com (mailing list archive)
State RFC
Headers show
Series KEYS: Introduce user asymmetric keys and signatures | expand

Checks

Context Check Description
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-2 success Logs for build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-4 success Logs for build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-5 success Logs for build for x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-6 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-3 success Logs for build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-25 success Logs for test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-27 success Logs for test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-28 success Logs for test_verifier on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-29 success Logs for veristat
bpf/vmtest-bpf-next-VM_Test-7 success Logs for test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-9 success Logs for test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-10 success Logs for test_maps on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-11 success Logs for test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-13 success Logs for test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-14 success Logs for test_progs on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-15 fail Logs for test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-17 success Logs for test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-18 success Logs for test_progs_no_alu32 on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-19 success Logs for test_progs_no_alu32_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-20 success Logs for test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-21 success Logs for test_progs_no_alu32_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-22 success Logs for test_progs_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-23 success Logs for test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-24 success Logs for test_progs_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-26 success Logs for test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-16 success Logs for test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-12 success Logs for test_progs on s390x with gcc
bpf/vmtest-bpf-next-PR fail PR summary
bpf/vmtest-bpf-next-VM_Test-8 success Logs for test_maps on s390x with gcc
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Guessed tree name to be net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit fail Errors and warnings before: 1341 this patch: 1356
netdev/cc_maintainers success CCed 7 of 7 maintainers
netdev/build_clang fail Errors and warnings before: 1364 this patch: 1370
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn fail Errors and warnings before: 1364 this patch: 1374
netdev/checkpatch fail CHECK: Concatenated strings should use spaces between elements ERROR: Macros with complex values should be enclosed in parentheses WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
netdev/kdoc fail Errors and warnings before: 0 this patch: 2
netdev/source_inline success Was 0 now: 0

Commit Message

Roberto Sassu July 6, 2023, 2:42 p.m. UTC
From: Roberto Sassu <roberto.sassu@huawei.com>

Introduce the common parser for user asymmetric keys and signatures. The
data format is TLV-based, and consists of a header and the data.

Key and signature blobs can be parsed with the new function uasym_parse().
Each caller of that function should provide a callback function,
responsible to parse their fields, and an opaque data pointer to be used by
the callback function to store the parsed data.

The same data format will be used to store both keys and signatures, albeit
with different fields.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
 crypto/asymmetric_keys/Kconfig        |  12 ++
 crypto/asymmetric_keys/Makefile       |   7 +
 crypto/asymmetric_keys/uasym_parser.c | 201 ++++++++++++++++++++++++++
 crypto/asymmetric_keys/uasym_parser.h |  30 ++++
 include/uapi/linux/uasym_parser.h     |  91 ++++++++++++
 5 files changed, 341 insertions(+)
 create mode 100644 crypto/asymmetric_keys/uasym_parser.c
 create mode 100644 crypto/asymmetric_keys/uasym_parser.h
 create mode 100644 include/uapi/linux/uasym_parser.h
diff mbox series

Patch

diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
index 1ef3b46d6f6..4f86fe78efd 100644
--- a/crypto/asymmetric_keys/Kconfig
+++ b/crypto/asymmetric_keys/Kconfig
@@ -85,4 +85,16 @@  config FIPS_SIGNATURE_SELFTEST
 	depends on ASYMMETRIC_KEY_TYPE
 	depends on PKCS7_MESSAGE_PARSER=X509_CERTIFICATE_PARSER
 
+config UASYM_KEYS_SIGS
+	tristate "User asymmetric keys and signatures"
+	depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE
+	help
+	  This option enables user asymmetric keys and signatures. They are
+	  keys and signatures converted in user space from their native
+	  format (e.g. PGP), to the TLV format (Type-Length-Value) understood
+	  by the kernel.
+
+	  Key and signature-specific fields are defined in the UAPI interface,
+	  so that user space converters can reference them.
+
 endif # ASYMMETRIC_KEY_TYPE
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
index 0d1fa1b692c..ac3955d834f 100644
--- a/crypto/asymmetric_keys/Makefile
+++ b/crypto/asymmetric_keys/Makefile
@@ -76,3 +76,10 @@  verify_signed_pefile-y := \
 
 $(obj)/mscode_parser.o: $(obj)/mscode.asn1.h $(obj)/mscode.asn1.h
 $(obj)/mscode.asn1.o: $(obj)/mscode.asn1.c $(obj)/mscode.asn1.h
+
+#
+# User asymmetric keys and signatures
+#
+obj-$(CONFIG_UASYM_KEYS_SIGS) += uasym_keys_sigs.o
+uasym_keys_sigs-y := \
+	uasym_parser.o
diff --git a/crypto/asymmetric_keys/uasym_parser.c b/crypto/asymmetric_keys/uasym_parser.c
new file mode 100644
index 00000000000..e207f350c40
--- /dev/null
+++ b/crypto/asymmetric_keys/uasym_parser.c
@@ -0,0 +1,201 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Huawei Technologies Duesseldorf GmbH
+ *
+ * Author: Roberto Sassu <roberto.sassu@huawei.com>
+ *
+ * Implement the user asymmetric keys and signature parser.
+ */
+
+#define pr_fmt(fmt) "UASYM PARSER: "fmt
+
+#include "uasym_parser.h"
+
+const char *data_types_str[] = {
+	FOR_EACH_DATA_TYPE(GENERATE_STRING)
+};
+
+const char *fields_str[] = {
+	FOR_EACH_FIELD(GENERATE_STRING)
+};
+
+/**
+ * uasym_parse_hdr - Parse a user asymmetric key or signature header
+ * @data: Data to parse (updated)
+ * @data_len: Length of @data (updated)
+ * @data_type: Data type (updated)
+ * @num_fields: Data fields (updated)
+ * @total_len: Length of key or signature, excluding the header (updated)
+ *
+ * Parse the header of a user asymmetric key or signature, update the data
+ * pointer and length, and provide the data type, number of fields and the
+ * length of that element.
+ *
+ * Return: Zero on success, a negative value on error.
+ */
+int uasym_parse_hdr(const u8 **data, size_t *data_len, u8 *data_type,
+		    u16 *num_fields, u64 *total_len)
+{
+	struct uasym_hdr *hdr;
+
+	if (*data_len < sizeof(*hdr)) {
+		pr_debug("Data blob too short, %lu bytes, expected %lu\n",
+			 *data_len, sizeof(*hdr));
+		return -EBADMSG;
+	}
+
+	hdr = (struct uasym_hdr *)*data;
+
+	*data += sizeof(*hdr);
+	*data_len -= sizeof(*hdr);
+
+	*data_type = hdr->data_type;
+	if (*data_type >= TYPE__LAST) {
+		pr_debug("Invalid data type %u\n", *data_type);
+		return -EBADMSG;
+	}
+
+	if (hdr->_reserved0 != 0) {
+		pr_debug("_reserved0 must be zero\n");
+		return -EBADMSG;
+	}
+
+	*num_fields = be16_to_cpu(hdr->num_fields);
+	if (*num_fields >= FIELD__LAST) {
+		pr_debug("Too many fields %u, max: %u\n", *num_fields,
+			 FIELD__LAST);
+		return -EBADMSG;
+	}
+
+	if (hdr->_reserved1 != 0) {
+		pr_debug("_reserved1 must be zero\n");
+		return -EBADMSG;
+	}
+
+	*total_len = be64_to_cpu(hdr->total_len);
+	if (*total_len > *data_len) {
+		pr_debug("Invalid total length %llu, expected: %lu\n",
+			 *total_len, *data_len);
+		return -EBADMSG;
+	}
+
+	pr_debug("Header: type: %s, num fields: %d, total len: %lld\n",
+		 data_types_str[hdr->data_type], *num_fields, *total_len);
+
+	return 0;
+}
+
+/**
+ * uasym_parse_data - Parse a user asymmetric key or signature data
+ * @callback: Callback function to call to parse the fields
+ * @callback_data: Opaque data to supply to the callback function
+ * @num_fields: Data fields
+ * @data: Data to parse
+ * @data_len: Length of @data
+ *
+ * Parse the data part of a user asymmetric key or signature and call the
+ * supplied callback function for each data field, passing also the opaque
+ * data pointer.
+ *
+ * Return: Zero on success, a negative value on error.
+ */
+int uasym_parse_data(parse_callback callback, void *callback_data,
+		     u16 num_fields, const u8 *data, size_t data_len)
+{
+	const u8 *data_ptr = data;
+	struct uasym_entry *entry;
+	u16 field;
+	u32 len;
+	int ret, i;
+
+	for (i = 0; i < num_fields; i++) {
+		if (data_len < sizeof(*entry))
+			return -EBADMSG;
+
+		entry = (struct uasym_entry *)data_ptr;
+		data_ptr += sizeof(*entry);
+		data_len -= sizeof(*entry);
+
+		field = be16_to_cpu(entry->field);
+		len = be32_to_cpu(entry->length);
+
+		if (data_len < len)
+			return -EBADMSG;
+
+		pr_debug("Data: field: %s, len: %d\n", fields_str[field], len);
+
+		if (!len)
+			continue;
+
+		ret = callback(callback_data, field, data_ptr, len);
+		if (ret < 0) {
+			pr_debug("Parsing of field %s failed, ret: %d\n",
+				 fields_str[field], ret);
+			return -EBADMSG;
+		}
+
+		data_ptr += len;
+		data_len -= len;
+	}
+
+	if (data_len) {
+		pr_debug("Excess data: %ld bytes\n", data_len);
+		return -EBADMSG;
+	}
+
+	return 0;
+}
+
+/**
+ * uasym_parse - Parse a user asymmetric key or signature
+ * @expected_data_type: Desired data type
+ * @callback: Callback function to call to parse the fields
+ * @callback_data: Opaque data to supply to the callback function
+ * @data: Data to parse
+ * @data_len: Length of @data
+ *
+ * Parse a user asymmetric key or signature and call the supplied callback
+ * function for each data field, passing also the opaque data pointer.
+ *
+ * Return: Zero on success, a negative value on error.
+ */
+int uasym_parse(enum data_types expected_data_type, parse_callback callback,
+		void *callback_data, const u8 *data, size_t data_len)
+{
+	u8 data_type;
+	u16 num_fields;
+	u64 total_len;
+	int ret = 0;
+
+	pr_debug("Start parsing data blob, size: %ld, expected data type: %s\n",
+		 data_len, data_types_str[expected_data_type]);
+
+	while (data_len) {
+		ret = uasym_parse_hdr(&data, &data_len, &data_type, &num_fields,
+				      &total_len);
+		if (ret < 0)
+			goto out;
+
+		if (data_type == expected_data_type)
+			break;
+
+		/*
+		 * uasym_parse_hdr() already checked that total_len <= data_len.
+		 */
+		data += total_len;
+		data_len -= total_len;
+	}
+
+	if (!data_len) {
+		pr_debug("Data type %s not found\n",
+			 data_types_str[expected_data_type]);
+		ret = -ENOENT;
+		goto out;
+	}
+
+	ret = uasym_parse_data(callback, callback_data, num_fields, data,
+			       total_len);
+out:
+	pr_debug("End of parsing data blob, ret: %d\n", ret);
+	return ret;
+}
diff --git a/crypto/asymmetric_keys/uasym_parser.h b/crypto/asymmetric_keys/uasym_parser.h
new file mode 100644
index 00000000000..985dda6aad3
--- /dev/null
+++ b/crypto/asymmetric_keys/uasym_parser.h
@@ -0,0 +1,30 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2023 Huawei Technologies Duesseldorf GmbH
+ *
+ * Author: Roberto Sassu <roberto.sassu@huawei.com>
+ *
+ * Header file of user asymmetric keys and signatures.
+ */
+
+#include <keys/asymmetric-subtype.h>
+#include <keys/asymmetric-parser.h>
+
+#include <uapi/linux/uasym_parser.h>
+
+#define kenter(FMT, ...) \
+	pr_debug("==> %s("FMT")\n", __func__, ##__VA_ARGS__)
+#define kleave(FMT, ...) \
+	pr_debug("<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
+
+typedef int (*parse_callback)(void *, enum fields, const u8 *, u32);
+
+extern const char *data_types_str[];
+extern const char *fields_str[];
+
+int uasym_parse_hdr(const u8 **data, size_t *data_len, u8 *data_type,
+		    u16 *num_fields, u64 *total_len);
+int uasym_parse_data(parse_callback callback, void *callback_data,
+		     u16 num_fields, const u8 *data, size_t data_len);
+int uasym_parse(enum data_types expected_data_type, parse_callback callback,
+		void *callback_data, const u8 *data, size_t data_len);
diff --git a/include/uapi/linux/uasym_parser.h b/include/uapi/linux/uasym_parser.h
new file mode 100644
index 00000000000..8f0bc235492
--- /dev/null
+++ b/include/uapi/linux/uasym_parser.h
@@ -0,0 +1,91 @@ 
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * Copyright (C) 2023 Huawei Technologies Duesseldorf GmbH
+ *
+ * Author: Roberto Sassu <roberto.sassu@huawei.com>
+ *
+ * Implement the user space interface for user asymmetric keys and signatures.
+ */
+
+#ifndef _UAPI_LINUX_UASYM_PARSER_H
+#define _UAPI_LINUX_UASYM_PARSER_H
+
+#include <linux/types.h>
+#include <linux/pub_key_info.h>
+
+/*
+ * User asymmmetric key and signature format:
+ *
+ * +----------------+-----------------+-----------------+
+ * | data type (u8) | num fields (u16)| total len (u64) |
+ * +--------------+-+----------+------+-----------+-----+
+ * | field1 (u16) | len1 (u32) | value1 (u8 len1) |
+ * +--------------+------------+------------------+
+ * |     ...      |    ...     |        ...       |
+ * +--------------+------------+------------------+
+ * | fieldN (u16) | lenN (u32) | valueN (u8 lenN) |
+ * +--------------+------------+------------------+
+ */
+
+/**
+ * struct uasym_hdr - Header of user asymmetric keys and signatures
+ * @data_type: Type of data to parse
+ * @_reserved0: Reserved for future use
+ * @num_fields: Number of fields provided
+ * @_reserved1: Reserved for future use
+ * @total_len: Total length of the data blob, excluding the header
+ *
+ * This structure represents the header of the user asymmetric keys and
+ * signatures format.
+ */
+struct uasym_hdr {
+	__u8 data_type;
+	__u8 _reserved0;
+	__u16 num_fields;
+	__u32 _reserved1;
+	__u64 total_len;
+} __packed;
+
+/**
+ * struct uasym_entry - Data entry of user asymmetric keys and signatures
+ * @field: Data field identifier
+ * @length: Data length
+ * @data: Data
+ *
+ * This structure represents a TLV entry of the data part of the user
+ * asymmetric keys and signatures format.
+ */
+struct uasym_entry {
+	__u16 field;
+	__u32 length;
+	__u8 data[];
+} __packed;
+
+#define FOR_EACH_DATA_TYPE(DATA_TYPE) \
+	DATA_TYPE(TYPE__LAST)
+
+#define FOR_EACH_FIELD(FIELD) \
+	FIELD(FIELD__LAST)
+
+#define GENERATE_ENUM(ENUM) ENUM,
+#define GENERATE_STRING(STRING) #STRING,
+
+/**
+ * enum data_types - Type of data to parse
+ *
+ * Enumerates the type of data to parse.
+ */
+enum data_types {
+	FOR_EACH_DATA_TYPE(GENERATE_ENUM)
+};
+
+/**
+ * enum fields - Data fields
+ *
+ * Enumerates the data fields. Some belongs to keys, some to signatures.
+ */
+enum fields {
+	FOR_EACH_FIELD(GENERATE_ENUM)
+};
+
+#endif /* _UAPI_LINUX_UASYM_PARSER_H */