All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/4] key: Update restrict method name
@ 2016-07-20 22:19 Mat Martineau
  2016-07-20 22:19 ` [PATCH 2/4] key: Consistently return errno from syscall wrappers Mat Martineau
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Mat Martineau @ 2016-07-20 22:19 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 581 bytes --]

Kernel now uses "restrict_by=keyring" instead of
"restrict_by=signature_keyring".
---
 ell/key.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ell/key.c b/ell/key.c
index e6ae92a..6117e31 100644
--- a/ell/key.c
+++ b/ell/key.c
@@ -243,7 +243,7 @@ LIB_EXPORT struct l_keyring *l_keyring_new(enum l_keyring_type type,
 
 		payload = l_strdup_printf(
 			"restrict_type=asymmetric "
-			"restrict_by=signature_keyring "
+			"restrict_by=keyring "
 			"restrict_key=%d",
 			trusted->serial);
 		payload_length = strlen(payload);
-- 
2.9.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/4] key: Consistently return errno from syscall wrappers
  2016-07-20 22:19 [PATCH 1/4] key: Update restrict method name Mat Martineau
@ 2016-07-20 22:19 ` Mat Martineau
  2016-07-21 20:19   ` Denis Kenzior
  2016-07-20 22:19 ` [PATCH 3/4] key: Add key-based asymmetric crypto operations Mat Martineau
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 9+ messages in thread
From: Mat Martineau @ 2016-07-20 22:19 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 2566 bytes --]

---
 ell/key.c | 43 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 36 insertions(+), 7 deletions(-)

diff --git a/ell/key.c b/ell/key.c
index 6117e31..60602f9 100644
--- a/ell/key.c
+++ b/ell/key.c
@@ -64,43 +64,72 @@ static const char * const key_type_names[] = {
 static long kernel_add_key(const char *type, const char *description,
 				const void *payload, size_t len, int32_t keyring)
 {
-	return syscall(__NR_add_key, type, description, payload, len, keyring);
+	long result;
+
+	result = syscall(__NR_add_key, type, description, payload, len,
+				keyring);
+
+	return result >= 0 ? result : -errno;
 }
 
 static long kernel_read_key(int32_t serial, const void *payload, size_t len)
 {
-	return syscall(__NR_keyctl, KEYCTL_READ, serial, payload, len);
+	long result;
+
+	result = syscall(__NR_keyctl, KEYCTL_READ, serial, payload, len);
+
+	return result >= 0 ? result : -errno;
 }
 
 static long kernel_update_key(int32_t serial, const void *payload, size_t len)
 {
-	return syscall(__NR_keyctl, KEYCTL_UPDATE, serial, payload, len);
+	long result;
+
+	result = syscall(__NR_keyctl, KEYCTL_UPDATE, serial, payload, len);
+
+	return result >= 0 ? result : -errno;
 }
 
 static long kernel_revoke_key(int32_t serial)
 {
-	return syscall(__NR_keyctl, KEYCTL_REVOKE, serial);
+	long result;
+
+	result = syscall(__NR_keyctl, KEYCTL_REVOKE, serial);
+
+	return result >= 0 ? result : -errno;
 }
 
 static long kernel_link_key(int32_t key_serial, int32_t ring_serial)
 {
-	return syscall(__NR_keyctl, KEYCTL_LINK, key_serial, ring_serial);
+	long result;
+
+	result = syscall(__NR_keyctl, KEYCTL_LINK, key_serial, ring_serial);
+
+	return result >= 0 ? result : -errno;
 }
 
 static long kernel_unlink_key(int32_t key_serial, int32_t ring_serial)
 {
-	return syscall(__NR_keyctl, KEYCTL_UNLINK, key_serial, ring_serial);
+	long result;
+
+	result = syscall(__NR_keyctl, KEYCTL_UNLINK, key_serial, ring_serial);
+
+	return result >= 0 ? result : -errno;
 }
 
 static long kernel_dh_compute(int32_t private, int32_t prime, int32_t base,
 			      void *payload, size_t len)
 {
+	long result;
+
 	struct keyctl_dh_params params = { .private = private,
 					   .prime = prime,
 					   .base = base };
 
-	return syscall(__NR_keyctl, KEYCTL_DH_COMPUTE, &params, payload, len,
+	result = syscall(__NR_keyctl, KEYCTL_DH_COMPUTE, &params, payload, len,
 			NULL);
+
+	return result >= 0 ? result : -errno;
 }
 
 static bool setup_internal_keyring(void)
-- 
2.9.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 3/4] key: Add key-based asymmetric crypto operations
  2016-07-20 22:19 [PATCH 1/4] key: Update restrict method name Mat Martineau
  2016-07-20 22:19 ` [PATCH 2/4] key: Consistently return errno from syscall wrappers Mat Martineau
@ 2016-07-20 22:19 ` Mat Martineau
  2016-07-22 19:35   ` Denis Kenzior
  2016-07-20 22:19 ` [PATCH 4/4] unit: Add tests for key-based asymmetric crypto Mat Martineau
  2016-07-21 20:19 ` [PATCH 1/4] key: Update restrict method name Denis Kenzior
  3 siblings, 1 reply; 9+ messages in thread
From: Mat Martineau @ 2016-07-20 22:19 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 8388 bytes --]

The kernel (as of v4.8) has asymmetric crypto methods available using
the keyctl API which make use of the kernel keyrings. The main
advantage of this API over AF_ALG is that typical asymmetric
operations involve fewer system calls.
---
 ell/key.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ell/key.h |  21 +++++++
 2 files changed, 221 insertions(+)

diff --git a/ell/key.c b/ell/key.c
index 60602f9..85e461f 100644
--- a/ell/key.c
+++ b/ell/key.c
@@ -29,10 +29,12 @@
 #include <stdint.h>
 #include <sys/syscall.h>
 #include <linux/keyctl.h>
+#include <errno.h>
 
 #include "private.h"
 #include "util.h"
 #include "key.h"
+#include "string.h"
 
 #ifndef KEYCTL_DH_COMPUTE
 #define KEYCTL_DH_COMPUTE 23
@@ -44,11 +46,47 @@ struct keyctl_dh_params {
 };
 #endif
 
+#ifndef KEYCTL_PKEY_QUERY
+#define KEYCTL_PKEY_QUERY	24
+#define KEYCTL_PKEY_ENCRYPT	25
+#define KEYCTL_PKEY_DECRYPT	26
+#define KEYCTL_PKEY_SIGN	27
+#define KEYCTL_PKEY_VERIFY	28
+
+#define KEYCTL_SUPPORTS_ENCRYPT	0x01
+#define KEYCTL_SUPPORTS_DECRYPT	0x02
+#define KEYCTL_SUPPORTS_SIGN	0x04
+#define KEYCTL_SUPPORTS_VERIFY	0x08
+
+struct keyctl_pkey_query {
+	uint32_t supported_ops;
+	uint32_t key_size;
+	uint16_t max_data_size;
+	uint16_t max_sig_size;
+	uint16_t max_enc_size;
+	uint16_t max_dec_size;
+
+	uint32_t __spare[10];
+};
+
+struct keyctl_pkey_params {
+	int32_t key_id;
+	uint32_t in_len;
+	union {
+		uint32_t out_len;
+		uint32_t in2_len;
+	};
+	uint32_t __spare[7];
+};
+#endif
+
 static int32_t internal_keyring;
 
 struct l_key {
 	int type;
 	int32_t serial;
+	char *encoding;
+	char *hash;
 };
 
 struct l_keyring {
@@ -117,6 +155,43 @@ static long kernel_unlink_key(int32_t key_serial, int32_t ring_serial)
 	return result >= 0 ? result : -errno;
 }
 
+static char *format_key_info(const char *encoding, const char *hash)
+{
+	struct l_string *info;
+
+	if (!encoding && !hash)
+		return NULL;
+
+	info = l_string_new(0);
+
+	if (encoding)
+		l_string_append_printf(info, "enc=%s ", encoding);
+
+	if (hash)
+		l_string_append_printf(info, "hash=%s", hash);
+
+	return l_string_free(info, false);
+}
+
+static long kernel_query_key(int32_t key_serial, size_t *size, bool *public,
+				const char *encoding, const char *hash)
+{
+	long result;
+	struct keyctl_pkey_query query;
+	char *info = format_key_info(encoding, hash);
+
+	result = syscall(__NR_keyctl, KEYCTL_PKEY_QUERY, key_serial, 0,
+				info ?: "", &query);
+	if (result == 0) {
+		*size = query.key_size;
+		*public = ((query.supported_ops & KEYCTL_SUPPORTS_ENCRYPT) &&
+			!(query.supported_ops & KEYCTL_SUPPORTS_DECRYPT));
+	}
+	l_free(info);
+
+	return result >= 0 ? result : -errno;
+}
+
 static long kernel_dh_compute(int32_t private, int32_t prime, int32_t base,
 			      void *payload, size_t len)
 {
@@ -132,6 +207,40 @@ static long kernel_dh_compute(int32_t private, int32_t prime, int32_t base,
 	return result >= 0 ? result : -errno;
 }
 
+static long kernel_key_eds(int op, int32_t serial, const char *encoding,
+				const char *hash, const void *in, void *out,
+				size_t len_in, size_t len_out)
+{
+	long result;
+	struct keyctl_pkey_params params = { .key_id = serial,
+					     .in_len = len_in,
+					     .out_len = len_out };
+	char *info = format_key_info(encoding, hash);
+
+	result = syscall(__NR_keyctl, op, &params, info ?: "", in, out);
+	l_free(info);
+
+	return result >= 0 ? result : -errno;
+}
+
+static long kernel_key_verify(int32_t serial, const char *encoding,
+				const char *hash, const void *data,
+				const void *sig, size_t len_data,
+				size_t len_sig)
+{
+	long result;
+	struct keyctl_pkey_params params = { .key_id = serial,
+					     .in_len = len_data,
+					     .in2_len = len_sig };
+	char *info = format_key_info(encoding, hash);
+
+	result = syscall(__NR_keyctl, KEYCTL_PKEY_VERIFY, &params, info ?: "",
+				data, sig);
+	l_free(info);
+
+	return result >= 0 ? result : -errno;
+}
+
 static bool setup_internal_keyring(void)
 {
 	internal_keyring = kernel_add_key("keyring", "ell-internal", NULL, 0,
@@ -220,6 +329,12 @@ LIB_EXPORT ssize_t l_key_get_size(struct l_key *key)
 	return kernel_read_key(key->serial, NULL, 0);
 }
 
+bool l_key_get_info(struct l_key *key, size_t *bits, bool *public)
+{
+	return !kernel_query_key(key->serial, bits, public, key->encoding,
+					key->hash);
+}
+
 static bool compute_common(struct l_key *base,
 			   struct l_key *private,
 			   struct l_key *prime,
@@ -255,6 +370,91 @@ LIB_EXPORT bool l_key_compute_dh_secret(struct l_key *other_public,
 	return compute_common(other_public, private, prime, payload, len);
 }
 
+LIB_EXPORT bool l_key_set_cipher(struct l_key *key,
+					enum l_asymmetric_cipher_type cipher)
+{
+	if (unlikely(!key))
+		return false;
+
+	switch (cipher) {
+	case L_CIPHER_RSA_PKCS1_V1_5:
+		key->encoding = "pkcs1";
+		break;
+	}
+
+	return true;
+}
+
+LIB_EXPORT bool l_key_set_checksum_info(struct l_key *key,
+					enum l_checksum_type checksum)
+{
+	if (unlikely(!key))
+		return false;
+
+	switch (checksum) {
+	case L_CHECKSUM_MD5:
+		key->hash = "md5";
+		break;
+	case L_CHECKSUM_SHA1:
+		key->hash = "sha1";
+		break;
+	case L_CHECKSUM_SHA256:
+		key->hash = "sha256";
+		break;
+	case L_CHECKSUM_SHA384:
+		key->hash = "sha384";
+		break;
+	case L_CHECKSUM_SHA512:
+		key->hash = "sha512";
+		break;
+	}
+
+	return true;
+}
+
+static ssize_t eds_common(struct l_key *key, const void *in, void *out,
+				size_t len_in, size_t len_out, int op)
+{
+	if (unlikely(!key))
+		return -EINVAL;
+
+	return kernel_key_eds(op, key->serial, key->encoding, key->hash, in,
+				out, len_in, len_out);
+}
+
+LIB_EXPORT ssize_t l_key_encrypt(struct l_key *key, const void *in, void *out,
+			size_t len_in, size_t len_out)
+{
+	return eds_common(key, in, out, len_in, len_out, KEYCTL_PKEY_ENCRYPT);
+}
+
+LIB_EXPORT ssize_t l_key_decrypt(struct l_key *key, const void *in, void *out,
+			size_t len_in, size_t len_out)
+{
+	return eds_common(key, in, out, len_in, len_out, KEYCTL_PKEY_DECRYPT);
+}
+
+LIB_EXPORT ssize_t l_key_sign(struct l_key *key, const void *in, void *out,
+			size_t len_in, size_t len_out)
+{
+	return eds_common(key, in, out, len_in, len_out, KEYCTL_PKEY_SIGN);
+}
+
+LIB_EXPORT bool l_key_verify(struct l_key *key, const void *data,
+				const void *sig, size_t len_data,
+				size_t len_sig)
+{
+	long result;
+
+	if (unlikely(!key))
+		return false;
+
+	result = kernel_key_verify(key->serial, key->encoding, key->hash,
+					data, sig, len_data, len_sig);
+
+	return result == 0;
+}
+
 LIB_EXPORT struct l_keyring *l_keyring_new(enum l_keyring_type type,
 						const struct l_keyring *trusted)
 {
diff --git a/ell/key.h b/ell/key.h
index 5d981f1..f5176d1 100644
--- a/ell/key.h
+++ b/ell/key.h
@@ -30,6 +30,9 @@ extern "C" {
 #include <stddef.h>
 #include <stdbool.h>
 
+#include <ell/checksum.h>
+#include <ell/cipher.h>
+
 struct l_key;
 struct l_keyring;
 
@@ -54,12 +57,30 @@ bool l_key_extract(struct l_key *key, void *payload, size_t *len);
 
 ssize_t l_key_get_size(struct l_key *key);
 
+bool l_key_get_info(struct l_key *key, size_t *bits, bool *public);
+
 bool l_key_compute_dh_public(struct l_key *generator, struct l_key *private,
 			     struct l_key *prime, void *payload, size_t *len);
 
 bool l_key_compute_dh_secret(struct l_key *other_public, struct l_key *private,
 			     struct l_key *prime, void *payload, size_t *len);
 
+bool l_key_set_cipher(struct l_key *key, enum l_asymmetric_cipher_type cipher);
+
+bool l_key_set_checksum_info(struct l_key *key, enum l_checksum_type checksum);
+
+ssize_t l_key_encrypt(struct l_key *key, const void *in, void *out,
+			size_t len_in, size_t len_out);
+
+ssize_t l_key_decrypt(struct l_key *key, const void *in, void *out,
+			size_t len_in, size_t len_out);
+
+ssize_t l_key_sign(struct l_key *key, const void *in, void *out,
+			size_t len_in, size_t len_out);
+
+bool l_key_verify(struct l_key *key, const void *data, const void *sig,
+			size_t len_data, size_t len_sig);
+
 struct l_keyring *l_keyring_new(enum l_keyring_type type,
 				const struct l_keyring *trust);
 
-- 
2.9.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 4/4] unit: Add tests for key-based asymmetric crypto
  2016-07-20 22:19 [PATCH 1/4] key: Update restrict method name Mat Martineau
  2016-07-20 22:19 ` [PATCH 2/4] key: Consistently return errno from syscall wrappers Mat Martineau
  2016-07-20 22:19 ` [PATCH 3/4] key: Add key-based asymmetric crypto operations Mat Martineau
@ 2016-07-20 22:19 ` Mat Martineau
  2016-07-21 20:19 ` [PATCH 1/4] key: Update restrict method name Denis Kenzior
  3 siblings, 0 replies; 9+ messages in thread
From: Mat Martineau @ 2016-07-20 22:19 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 11657 bytes --]

---
 unit/cert-client-key-pkcs8.pem |  28 ++++++
 unit/gencerts.sh               |   1 +
 unit/test-key.c                | 196 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 225 insertions(+)
 create mode 100644 unit/cert-client-key-pkcs8.pem

diff --git a/unit/cert-client-key-pkcs8.pem b/unit/cert-client-key-pkcs8.pem
new file mode 100644
index 0000000..738b825
--- /dev/null
+++ b/unit/cert-client-key-pkcs8.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDhOQ/5VIWkwt8S
+9vNbbWT0VEV5Siai8HBxl0ErkJusMGFrQIS8jCxB668hNKAoSncN3lezZ/yDg8b5
+NUvLiLinx1rjXeal/8ruwowlr8optgkiRxduK0BZm/Xj6HXTmZwzDACM+zwt9uSV
+YW6/y0gS26oWdLJh8tRysq88xx8ylOGHEx/9/tx+DB2cJzWX23xuaoUWRjbrv/Lf
+gFlXBKHD0RmGac1iTaugAM6IwB0kjscYrHATIrkPgXaHz8PV4cKUvhbLZK7xfCfR
+X2Y+VNxTpvxIDkJ/Hn561C9t9T6gdUfTyCmL//d/Kd4gzCItBE4iouXHnVlfJtj3
+MpD3TTijAgMBAAECggEBAIbg9YAL7j1NtupUmkkWqm7oSPLqRVkvRSfBvXWplJD6
+KF1itht0lsyjqK3qJj/62HGlxj/a9o6MTIzSLiImLu/Lo9KmWYrwNUfnmqa3MArq
+yW2NxapknJUNoaRrgqTGSZUIiwvjKZcdVKdhQkH6K5+fja0FFg8yrahC+k8bsMNI
+5mw8NwRdR3SvHJWHCLfKCQ31tju7On/4C6jr0siUCc2//W+SO5c+FHDY1bma02cp
+jXTEiFpw91YcyKxiADIaH9/qfxWdefxqYg1WlUeXF3jYt5xYnYr34qKW1gOZ3jy1
+QJ3esn382ZTml3TFZWy+g9tkYyOSgmDwQZbLk/ppBAECgYEA8RzLBFwP018ieMBv
+khDtwcKk6ZihkWZxEPQPuUljWzzAHn/f3dXOcrfmflAKeoDEeYDimDYDizTLDPC4
+zmWkMJHNadcM5H065BbGVFQWXo47ltccfIlB/1vzG8aywfJ/yNfHvH87wbH2eg6N
+yOr+96ZjLJszQ+Rv189BbXDzTcMCgYEA7yEbUL/A1J0l2kLoYyS0vfVa7AyBVOFW
+vPgfkF7HdNpIiFWlukMr+DWOolaoZp5iHqQXFwJsL8qCcrbZuHbaNHAI/5vDE9xG
+fh8KzrfBrjIPIyNm6EWpsBo5unXK+wTeqIAGKdzDo5Q3zEE6G5DkkHItKA7yjPOM
+gz/b/MR3W6ECgYBBv3dA3hXWrreIs/j4nLMoxfoQVPWh34xvcg4jmXaFd6Bv8LDM
+HjRopestgIgK9bgd5d5kYT5AJIpGIhJS/fZy5B9egCzc1aVMc0Vr024yJJjtPgVf
+lFIx3xIA/gLazlS4INcveIaEABJVIEjbg/E4+N9MV5n4Jn+1GqgdvtIp3wKBgQC0
+C3lFkxrc+nVFoJrYCwsK+3E5yTCXeBKWtTsOuE307WUvQU1GsMyqVajPEfA5U4cN
+Cv9Xk7thQFh3hrTm7pXcZX5g9iYrDe8FhtncSv7I6Wf8TOtudwUMUrKkcYwi88ex
+lrMNUer7ft2ELJhTqQRuvYjCYH6/IaDqMWqxJju4AQKBgQDPjOh75ykQc93SsYpt
+Tb4gQKLeqOb57pofT8D44DccatfEgk31D4fBIIQu6XKopQmCtQyX9DUDjOWFTxuo
+IMPysN6Fh1quCbC6Xt5xfKoaJG5yQYKeKtLhknwEW9SUifU2xVrOcPikLs7Iwmmp
+BkDLsu/YKwRFSfrbYZXbTlU8tQ==
+-----END PRIVATE KEY-----
diff --git a/unit/gencerts.sh b/unit/gencerts.sh
index fb305d7..cfa6486 100755
--- a/unit/gencerts.sh
+++ b/unit/gencerts.sh
@@ -12,6 +12,7 @@ openssl verify -CAfile cert-ca.pem cert-server.pem
 
 echo -e "\n*** Client Certificate ***"
 openssl genrsa -out cert-client-key.pem
+openssl pkcs8 -topk8 -nocrypt -in cert-client-key.pem -out cert-client-key-pkcs8.pem
 openssl req -new -extensions cert_ext -config ./gencerts.cnf -subj '/O=Bar Example Organization/CN=Bar Example Organization/emailAddress=bar(a)mail.example' -key cert-client-key.pem -out cert-client.csr
 openssl x509 -req -extensions cert_ext -extfile ./gencerts.cnf -in cert-client.csr -CA cert-ca.pem -CAkey cert-ca-key.pem -CAcreateserial -sha256 -days 10000 -out cert-client.pem
 openssl verify -CAfile cert-ca.pem cert-client.pem
diff --git a/unit/test-key.c b/unit/test-key.c
index df1e13b..21eeb8a 100644
--- a/unit/test-key.c
+++ b/unit/test-key.c
@@ -33,6 +33,12 @@
 #define KEY2_STR "This key is longer than 32 bytes, just to be different."
 #define KEY2_LEN (strlen(KEY2_STR))
 
+static const char *plaintext =
+	"The quick brown fox jumps over the lazy dog. "	\
+	"Jackdaws love my big sphinx of quartz. "	\
+	"Pack my box with five dozen liquor jugs. "	\
+	"How razorback-jumping frogs can level six piqued gymnasts!";
+
 static void test_unsupported(const void *data)
 {
 	struct l_key *key;
@@ -400,6 +406,194 @@ static void test_trusted_keyring(const void *data)
 	l_free(cert);
 }
 
+/* Reference ciphertext:
+ * $ openssl rsautl -in reference_plaintext -inkey cert-client.pem -encrypt \
+ * > -pkcs -out reference_ciphertext
+ * $ xxd -i reference_ciphertext
+ *
+ * where reference_plaintext is a file containing the 183 characters of
+ * plaintext[] (above).
+ */
+static uint8_t reference_ciphertext[256] = {
+	0x45, 0x1a, 0xa1, 0x49, 0x4f, 0x61, 0xf6, 0x96, 0x23, 0x77, 0x0c, 0x33,
+	0x56, 0x07, 0xe6, 0x0f, 0xd6, 0x7b, 0x90, 0xd0, 0x4f, 0xc7, 0x9f, 0x34,
+	0xd4, 0x99, 0x55, 0x74, 0xd9, 0x68, 0x35, 0x3f, 0xd5, 0xbd, 0x7a, 0xec,
+	0xd3, 0xd1, 0x7e, 0xe3, 0xf0, 0xd6, 0x72, 0x7f, 0xb7, 0x20, 0x10, 0x53,
+	0x1c, 0xaa, 0x2b, 0xf6, 0x82, 0x66, 0xdf, 0xfe, 0x71, 0x62, 0x4e, 0x97,
+	0xdb, 0x83, 0xff, 0xc2, 0xab, 0x79, 0x69, 0xc7, 0xde, 0x77, 0x18, 0x55,
+	0x0c, 0xea, 0x01, 0x4e, 0xeb, 0x8b, 0x13, 0xa3, 0xef, 0xc4, 0x29, 0xa6,
+	0x51, 0x16, 0x3f, 0xa5, 0xe9, 0x91, 0x91, 0x26, 0x45, 0x98, 0x1f, 0x0b,
+	0x34, 0x6e, 0x4a, 0x61, 0xc4, 0xf3, 0x85, 0x78, 0x6b, 0xdf, 0x38, 0x9b,
+	0xeb, 0x6d, 0xc2, 0xed, 0xdf, 0xa9, 0xe6, 0xbb, 0x81, 0x84, 0xd9, 0x4a,
+	0x42, 0xa6, 0x3b, 0xa9, 0x5b, 0xae, 0xee, 0xaa, 0x6a, 0x3a, 0xc0, 0xcb,
+	0x48, 0x5c, 0x61, 0xa0, 0xe2, 0x4c, 0x06, 0x15, 0x7a, 0x8e, 0xe7, 0x47,
+	0x9c, 0x03, 0x86, 0x70, 0x00, 0xa1, 0xa8, 0x68, 0x9e, 0x7e, 0xc7, 0x81,
+	0x38, 0xb3, 0x00, 0xd4, 0xa9, 0xc2, 0x56, 0xf7, 0xf4, 0x3b, 0x9b, 0xb1,
+	0x27, 0xcd, 0xed, 0x2e, 0xf3, 0xa8, 0x9b, 0x08, 0x5e, 0x8a, 0xf3, 0x29,
+	0x67, 0xa4, 0x93, 0xc5, 0x68, 0xa5, 0x26, 0x1b, 0x3b, 0x1d, 0xc7, 0x78,
+	0x32, 0xd9, 0x81, 0x65, 0x8e, 0x17, 0xb3, 0x17, 0x30, 0x12, 0xe3, 0x78,
+	0x23, 0xd9, 0x02, 0x3b, 0xf9, 0x7b, 0x8d, 0x12, 0x4c, 0xff, 0xa0, 0xd2,
+	0x0f, 0x59, 0xb9, 0x75, 0xbd, 0x7f, 0xbb, 0x13, 0x8c, 0x6f, 0xbd, 0x00,
+	0x67, 0xf3, 0xa0, 0x43, 0x05, 0x5d, 0xb7, 0x64, 0xe3, 0xae, 0x81, 0xe1,
+	0x78, 0x5e, 0x81, 0xc5, 0x20, 0xc0, 0xdb, 0xba, 0xd0, 0xbe, 0x1f, 0xc5,
+	0x6a, 0xe4, 0x31, 0x46
+};
+
+/* Reference signature:
+ * $ openssl dgst -sha256 -sign cert-client-key.pem -out reference_signature \
+ * > good_plaintext
+ * $ xxd -i reference_signature
+ *
+ * where reference_plaintext is a file containing the 183 characters of
+ * plaintext[] (above).
+ */
+
+uint8_t reference_signature[256] = {
+	0x39, 0xaf, 0x0d, 0x23, 0x33, 0xcc, 0x48, 0xed, 0xc3, 0x15, 0x9e, 0xb9,
+	0xd3, 0x53, 0xe0, 0x0c, 0xea, 0x45, 0x65, 0xa7, 0x82, 0x8f, 0x4b, 0xfc,
+	0x5e, 0xd3, 0xc9, 0x10, 0xf5, 0xc6, 0x56, 0x3a, 0x0e, 0x60, 0xde, 0x01,
+	0xac, 0xb6, 0xf8, 0xc7, 0xe3, 0x60, 0xd1, 0xec, 0x4f, 0x38, 0x36, 0x42,
+	0xab, 0xf5, 0x90, 0xd6, 0xd8, 0x8b, 0x8a, 0x1c, 0x1a, 0xda, 0xec, 0x10,
+	0xd2, 0xec, 0x8a, 0x77, 0x9f, 0xcf, 0x25, 0x48, 0x13, 0xdf, 0xd0, 0xb1,
+	0xaf, 0x12, 0x55, 0xa0, 0x1a, 0xda, 0x8a, 0x60, 0xbf, 0x10, 0xcf, 0x02,
+	0xae, 0x3e, 0x7c, 0x01, 0x3f, 0x9d, 0xf4, 0xfb, 0x4b, 0x2c, 0x99, 0x7d,
+	0x0e, 0x06, 0xd5, 0x1e, 0x94, 0x38, 0x08, 0x18, 0x62, 0xb1, 0x73, 0x49,
+	0xae, 0x9f, 0x0e, 0x3b, 0x40, 0x48, 0x7f, 0x73, 0x73, 0xe0, 0x5c, 0xdf,
+	0xed, 0xb0, 0xf5, 0x9a, 0xbe, 0xa0, 0xff, 0x3f, 0x70, 0xe6, 0xe4, 0xf4,
+	0x99, 0x1a, 0x79, 0x1d, 0x76, 0x38, 0x8a, 0xae, 0x04, 0xba, 0x9a, 0xf7,
+	0x5e, 0x58, 0x5f, 0x4f, 0x86, 0x4b, 0x89, 0x2f, 0x6c, 0xf7, 0xf0, 0x42,
+	0x5e, 0x2f, 0x01, 0x6f, 0xb4, 0x7e, 0x7e, 0xa8, 0xeb, 0xa4, 0x7b, 0x03,
+	0x63, 0x61, 0x26, 0x1d, 0xc1, 0xba, 0xfa, 0xf3, 0xa9, 0xa4, 0xb1, 0x7e,
+	0x0a, 0x2f, 0x22, 0x30, 0x48, 0x16, 0xfb, 0x25, 0x13, 0x67, 0x86, 0x98,
+	0x39, 0x88, 0x31, 0x78, 0xb4, 0xfb, 0xe3, 0xa0, 0x2e, 0x5c, 0x97, 0xdd,
+	0xfa, 0xe1, 0xd8, 0x3e, 0xd2, 0x9f, 0x33, 0xa4, 0x65, 0xc8, 0x34, 0xa5,
+	0xe7, 0x57, 0x9a, 0xae, 0x97, 0x93, 0x17, 0xa4, 0x72, 0x85, 0x83, 0xc9,
+	0x64, 0x62, 0x58, 0xbf, 0x3b, 0xb4, 0xb8, 0x1f, 0x5c, 0xd5, 0x9a, 0x3f,
+	0x3a, 0xf8, 0xe1, 0x2d, 0x6a, 0xf3, 0x0c, 0x20, 0x6e, 0x87, 0xa6, 0xc8,
+	0xf4, 0x8e, 0x18, 0x07
+};
+
+static void test_key_crypto(const void *data)
+{
+	uint8_t *cert;
+	size_t certlen;
+	uint8_t *pubcert;
+	size_t pubcertlen;
+	struct l_key *key;
+	struct l_key *pubkey;
+	bool is_public;
+	size_t keybits;
+	bool success;
+	uint8_t ciphertext[256];
+	uint8_t decrypted[256];
+	uint8_t msghash[32];
+	ssize_t len;
+	struct l_checksum *checksum;
+
+	cert = l_pem_load_private_key(TESTDATADIR "/cert-client-key-pkcs8.pem",
+					NULL, &certlen);
+	assert(cert);
+	pubcert = l_pem_load_certificate(TESTDATADIR "/cert-client.pem",
+						&pubcertlen);
+	assert(pubcert);
+
+	key = l_key_new(L_KEY_ASYMMETRIC, cert, certlen);
+	assert(key);
+	pubkey = l_key_new(L_KEY_ASYMMETRIC, pubcert, pubcertlen);
+	assert(pubkey);
+
+	success = l_key_get_info(key, &keybits, &is_public);
+	assert(success);
+	assert(keybits == 2048);
+	assert(!is_public);
+
+	success = l_key_get_info(pubkey, &keybits, &is_public);
+	assert(success);
+	assert(keybits == 2048);
+	assert(is_public);
+
+	success = l_key_set_cipher(key, L_CIPHER_RSA_PKCS1_V1_5);
+	assert(success);
+	success = l_key_set_cipher(pubkey, L_CIPHER_RSA_PKCS1_V1_5);
+	assert(success);
+
+	success = l_key_set_checksum_info(key, L_CHECKSUM_SHA256);
+	assert(success);
+	success = l_key_set_checksum_info(pubkey, L_CHECKSUM_SHA256);
+	assert(success);
+
+	memset(ciphertext, 0, sizeof(ciphertext));
+	memset(decrypted, 0, sizeof(decrypted));
+
+	len = l_key_encrypt(pubkey, plaintext, ciphertext, strlen(plaintext),
+				sizeof(ciphertext));
+	assert(len == sizeof(ciphertext));
+
+	/* Can't decrypt with public key */
+	len = l_key_decrypt(pubkey, ciphertext, decrypted, sizeof(ciphertext),
+				sizeof(decrypted));
+	assert(len < 0);
+
+	len = l_key_decrypt(key, ciphertext, decrypted, sizeof(ciphertext),
+				sizeof(decrypted));
+	assert(len == (ssize_t)strlen(plaintext));
+	assert(strcmp(plaintext, (char *)decrypted) == 0);
+
+	/* Decrypt reference ciphertext */
+	memset(decrypted, 0, sizeof(decrypted));
+	len = l_key_decrypt(key, reference_ciphertext, decrypted,
+				sizeof(reference_ciphertext),
+				sizeof(decrypted));
+	assert(len == (ssize_t)strlen(plaintext));
+	assert(strcmp(plaintext, (char *)decrypted) == 0);
+
+	/* Decrypt corrupted ciphertext */
+	memset(decrypted, 0, sizeof(decrypted));
+	reference_ciphertext[0] = reference_ciphertext[0] ^ (uint8_t)0xFF;
+	len = l_key_decrypt(key, reference_ciphertext, decrypted,
+				sizeof(reference_ciphertext),
+				sizeof(decrypted));
+	assert(len < 0);
+
+	checksum = l_checksum_new(L_CHECKSUM_SHA256);
+	assert(checksum);
+	l_checksum_update(checksum, plaintext, strlen(plaintext));
+	l_checksum_get_digest(checksum, msghash, sizeof(msghash));
+	l_checksum_free(checksum);
+
+	/* Can't sign with public key */
+	len = l_key_sign(pubkey, msghash, ciphertext, sizeof(msghash),
+				sizeof(ciphertext));
+	assert(len < 0);
+
+	len = l_key_sign(key, msghash, ciphertext, sizeof(msghash),
+				sizeof(ciphertext));
+	assert(len == sizeof(ciphertext));
+
+	success = l_key_verify(pubkey, msghash, ciphertext, sizeof(msghash),
+				sizeof(ciphertext));
+	assert(success);
+
+	success = l_key_verify(key, msghash, ciphertext, sizeof(msghash),
+				sizeof(ciphertext));
+	assert(success);
+
+	success = l_key_verify(pubkey, msghash, reference_signature,
+				sizeof(msghash), sizeof(reference_signature));
+	assert(success);
+
+	/* Corrupt signature */
+	msghash[10] = msghash[10] ^ (uint8_t)0xFF;
+	success = l_key_verify(key, msghash, ciphertext, sizeof(msghash),
+				sizeof(ciphertext));
+	assert(!success);
+
+	l_key_free(key);
+	l_key_free(pubkey);
+	l_free(cert);
+	l_free(pubcert);
+}
+
 int main(int argc, char *argv[])
 {
 	l_test_init(&argc, &argv);
@@ -414,5 +608,7 @@ int main(int argc, char *argv[])
 	l_test_add("simple keyring", test_simple_keyring, NULL);
 	l_test_add("trusted keyring", test_trusted_keyring, NULL);
 
+	l_test_add("key crypto", test_key_crypto, NULL);
+
 	return l_test_run();
 }
-- 
2.9.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/4] key: Consistently return errno from syscall wrappers
  2016-07-20 22:19 ` [PATCH 2/4] key: Consistently return errno from syscall wrappers Mat Martineau
@ 2016-07-21 20:19   ` Denis Kenzior
  2016-07-21 21:23     ` Mat Martineau
  0 siblings, 1 reply; 9+ messages in thread
From: Denis Kenzior @ 2016-07-21 20:19 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 862 bytes --]

On 07/20/2016 05:19 PM, Mat Martineau wrote:
> ---
>   ell/key.c | 43 ++++++++++++++++++++++++++++++++++++-------
>   1 file changed, 36 insertions(+), 7 deletions(-)
>
> diff --git a/ell/key.c b/ell/key.c
> index 6117e31..60602f9 100644
> --- a/ell/key.c
> +++ b/ell/key.c
> @@ -64,43 +64,72 @@ static const char * const key_type_names[] = {
>   static long kernel_add_key(const char *type, const char *description,
>   				const void *payload, size_t len, int32_t keyring)
>   {
> -	return syscall(__NR_add_key, type, description, payload, len, keyring);
> +	long result;
> +
> +	result = syscall(__NR_add_key, type, description, payload, len,
> +				keyring);
> +
> +	return result >= 0 ? result : -errno;
>   }
>

I get lots of errno undeclared errors after this patch

Looks like #include <errno.h> is missing.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/4] key: Update restrict method name
  2016-07-20 22:19 [PATCH 1/4] key: Update restrict method name Mat Martineau
                   ` (2 preceding siblings ...)
  2016-07-20 22:19 ` [PATCH 4/4] unit: Add tests for key-based asymmetric crypto Mat Martineau
@ 2016-07-21 20:19 ` Denis Kenzior
  3 siblings, 0 replies; 9+ messages in thread
From: Denis Kenzior @ 2016-07-21 20:19 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 270 bytes --]

Hi Mat,

On 07/20/2016 05:19 PM, Mat Martineau wrote:
> Kernel now uses "restrict_by=keyring" instead of
> "restrict_by=signature_keyring".
> ---
>   ell/key.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
>

Applied, thanks.

Regards,
-Denis


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/4] key: Consistently return errno from syscall wrappers
  2016-07-21 20:19   ` Denis Kenzior
@ 2016-07-21 21:23     ` Mat Martineau
  0 siblings, 0 replies; 9+ messages in thread
From: Mat Martineau @ 2016-07-21 21:23 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 1105 bytes --]

On Thu, 21 Jul 2016, Denis Kenzior wrote:

> On 07/20/2016 05:19 PM, Mat Martineau wrote:
>> ---
>>   ell/key.c | 43 ++++++++++++++++++++++++++++++++++++-------
>>   1 file changed, 36 insertions(+), 7 deletions(-)
>> 
>> diff --git a/ell/key.c b/ell/key.c
>> index 6117e31..60602f9 100644
>> --- a/ell/key.c
>> +++ b/ell/key.c
>> @@ -64,43 +64,72 @@ static const char * const key_type_names[] = {
>>   static long kernel_add_key(const char *type, const char *description,
>>   				const void *payload, size_t len, int32_t 
>> keyring)
>>   {
>> -	return syscall(__NR_add_key, type, description, payload, len, 
>> keyring);
>> +	long result;
>> +
>> +	result = syscall(__NR_add_key, type, description, payload, len,
>> +				keyring);
>> +
>> +	return result >= 0 ? result : -errno;
>>   }
>> 
>
> I get lots of errno undeclared errors after this patch
>
> Looks like #include <errno.h> is missing.

That's what I get for reordering them. There are no conflicts between this 
patch and the last two, just apply it some time after patch 3/4.

--
Mat Martineau
Intel OTC

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 3/4] key: Add key-based asymmetric crypto operations
  2016-07-20 22:19 ` [PATCH 3/4] key: Add key-based asymmetric crypto operations Mat Martineau
@ 2016-07-22 19:35   ` Denis Kenzior
  2016-07-22 21:55     ` Mat Martineau
  0 siblings, 1 reply; 9+ messages in thread
From: Denis Kenzior @ 2016-07-22 19:35 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 9340 bytes --]

Hi Mat,

On 07/20/2016 05:19 PM, Mat Martineau wrote:
> The kernel (as of v4.8) has asymmetric crypto methods available using
> the keyctl API which make use of the kernel keyrings. The main
> advantage of this API over AF_ALG is that typical asymmetric
> operations involve fewer system calls.
> ---
>   ell/key.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>   ell/key.h |  21 +++++++
>   2 files changed, 221 insertions(+)
>
> diff --git a/ell/key.c b/ell/key.c
> index 60602f9..85e461f 100644
> --- a/ell/key.c
> +++ b/ell/key.c
> @@ -29,10 +29,12 @@
>   #include <stdint.h>
>   #include <sys/syscall.h>
>   #include <linux/keyctl.h>
> +#include <errno.h>
>
>   #include "private.h"
>   #include "util.h"
>   #include "key.h"
> +#include "string.h"
>
>   #ifndef KEYCTL_DH_COMPUTE
>   #define KEYCTL_DH_COMPUTE 23
> @@ -44,11 +46,47 @@ struct keyctl_dh_params {
>   };
>   #endif
>
> +#ifndef KEYCTL_PKEY_QUERY
> +#define KEYCTL_PKEY_QUERY	24
> +#define KEYCTL_PKEY_ENCRYPT	25
> +#define KEYCTL_PKEY_DECRYPT	26
> +#define KEYCTL_PKEY_SIGN	27
> +#define KEYCTL_PKEY_VERIFY	28
> +
> +#define KEYCTL_SUPPORTS_ENCRYPT	0x01
> +#define KEYCTL_SUPPORTS_DECRYPT	0x02
> +#define KEYCTL_SUPPORTS_SIGN	0x04
> +#define KEYCTL_SUPPORTS_VERIFY	0x08
> +
> +struct keyctl_pkey_query {
> +	uint32_t supported_ops;
> +	uint32_t key_size;
> +	uint16_t max_data_size;
> +	uint16_t max_sig_size;
> +	uint16_t max_enc_size;
> +	uint16_t max_dec_size;
> +
> +	uint32_t __spare[10];
> +};
> +
> +struct keyctl_pkey_params {
> +	int32_t key_id;
> +	uint32_t in_len;
> +	union {
> +		uint32_t out_len;
> +		uint32_t in2_len;
> +	};
> +	uint32_t __spare[7];
> +};
> +#endif
> +
>   static int32_t internal_keyring;
>
>   struct l_key {
>   	int type;
>   	int32_t serial;
> +	char *encoding;
> +	char *hash;

Should these be const char?

>   };
>
>   struct l_keyring {
> @@ -117,6 +155,43 @@ static long kernel_unlink_key(int32_t key_serial, int32_t ring_serial)
>   	return result >= 0 ? result : -errno;
>   }
>
> +static char *format_key_info(const char *encoding, const char *hash)
> +{
> +	struct l_string *info;
> +
> +	if (!encoding && !hash)
> +		return NULL;
> +
> +	info = l_string_new(0);
> +
> +	if (encoding)
> +		l_string_append_printf(info, "enc=%s ", encoding);
> +
> +	if (hash)
> +		l_string_append_printf(info, "hash=%s", hash);
> +
> +	return l_string_free(info, false);
> +}
> +
> +static long kernel_query_key(int32_t key_serial, size_t *size, bool *public,
> +				const char *encoding, const char *hash)
> +{
> +	long result;
> +	struct keyctl_pkey_query query;
> +	char *info = format_key_info(encoding, hash);
> +
> +	result = syscall(__NR_keyctl, KEYCTL_PKEY_QUERY, key_serial, 0,
> +				info ?: "", &query);
> +	if (result == 0) {
> +		*size = query.key_size;
> +		*public = ((query.supported_ops & KEYCTL_SUPPORTS_ENCRYPT) &&
> +			!(query.supported_ops & KEYCTL_SUPPORTS_DECRYPT));
> +	}
> +	l_free(info);
> +
> +	return result >= 0 ? result : -errno;
> +}
> +
>   static long kernel_dh_compute(int32_t private, int32_t prime, int32_t base,
>   			      void *payload, size_t len)
>   {
> @@ -132,6 +207,40 @@ static long kernel_dh_compute(int32_t private, int32_t prime, int32_t base,
>   	return result >= 0 ? result : -errno;
>   }
>
> +static long kernel_key_eds(int op, int32_t serial, const char *encoding,
> +				const char *hash, const void *in, void *out,
> +				size_t len_in, size_t len_out)
> +{
> +	long result;
> +	struct keyctl_pkey_params params = { .key_id = serial,
> +					     .in_len = len_in,
> +					     .out_len = len_out };
> +	char *info = format_key_info(encoding, hash);
> +
> +	result = syscall(__NR_keyctl, op, &params, info ?: "", in, out);
> +	l_free(info);
> +
> +	return result >= 0 ? result : -errno;
> +}
> +
> +static long kernel_key_verify(int32_t serial, const char *encoding,
> +				const char *hash, const void *data,
> +				const void *sig, size_t len_data,
> +				size_t len_sig)
> +{
> +	long result;
> +	struct keyctl_pkey_params params = { .key_id = serial,
> +					     .in_len = len_data,
> +					     .in2_len = len_sig };
> +	char *info = format_key_info(encoding, hash);
> +
> +	result = syscall(__NR_keyctl, KEYCTL_PKEY_VERIFY, &params, info ?: "",
> +				data, sig);
> +	l_free(info);
> +
> +	return result >= 0 ? result : -errno;
> +}
> +
>   static bool setup_internal_keyring(void)
>   {
>   	internal_keyring = kernel_add_key("keyring", "ell-internal", NULL, 0,
> @@ -220,6 +329,12 @@ LIB_EXPORT ssize_t l_key_get_size(struct l_key *key)
>   	return kernel_read_key(key->serial, NULL, 0);
>   }
>
> +bool l_key_get_info(struct l_key *key, size_t *bits, bool *public)
> +{
> +	return !kernel_query_key(key->serial, bits, public, key->encoding,
> +					key->hash);
> +}
> +

How is this related to l_key_get_size()?

We might want to start documenting the l_key methods...

>   static bool compute_common(struct l_key *base,
>   			   struct l_key *private,
>   			   struct l_key *prime,
> @@ -255,6 +370,91 @@ LIB_EXPORT bool l_key_compute_dh_secret(struct l_key *other_public,
>   	return compute_common(other_public, private, prime, payload, len);
>   }
>
> +LIB_EXPORT bool l_key_set_cipher(struct l_key *key,
> +					enum l_asymmetric_cipher_type cipher)
> +{
> +	if (unlikely(!key))
> +		return false;
> +
> +	switch (cipher) {
> +	case L_CIPHER_RSA_PKCS1_V1_5:
> +		key->encoding = "pkcs1";
> +		break;
> +	}
> +
> +	return true;
> +}
> +
> +LIB_EXPORT bool l_key_set_checksum_info(struct l_key *key,
> +					enum l_checksum_type checksum)
> +{
> +	if (unlikely(!key))
> +		return false;
> +
> +	switch (checksum) {
> +	case L_CHECKSUM_MD5:
> +		key->hash = "md5";
> +		break;
> +	case L_CHECKSUM_SHA1:
> +		key->hash = "sha1";
> +		break;
> +	case L_CHECKSUM_SHA256:
> +		key->hash = "sha256";
> +		break;
> +	case L_CHECKSUM_SHA384:
> +		key->hash = "sha384";
> +		break;
> +	case L_CHECKSUM_SHA512:
> +		key->hash = "sha512";
> +		break;
> +	}
> +
> +	return true;
> +}
> +
> +static ssize_t eds_common(struct l_key *key, const void *in, void *out,
> +				size_t len_in, size_t len_out, int op)

Whats eds stand for?

> +{
> +	if (unlikely(!key))
> +		return -EINVAL;
> +
> +	return kernel_key_eds(op, key->serial, key->encoding, key->hash, in,
> +				out, len_in, len_out);
> +}
> +
> +LIB_EXPORT ssize_t l_key_encrypt(struct l_key *key, const void *in, void *out,
> +			size_t len_in, size_t len_out)
> +{
> +	return eds_common(key, in, out, len_in, len_out, KEYCTL_PKEY_ENCRYPT);
> +}
> +
> +LIB_EXPORT ssize_t l_key_decrypt(struct l_key *key, const void *in, void *out,
> +			size_t len_in, size_t len_out)
> +{
> +	return eds_common(key, in, out, len_in, len_out, KEYCTL_PKEY_DECRYPT);
> +}
> +
> +LIB_EXPORT ssize_t l_key_sign(struct l_key *key, const void *in, void *out,
> +			size_t len_in, size_t len_out)
> +{
> +	return eds_common(key, in, out, len_in, len_out, KEYCTL_PKEY_SIGN);
> +}
> +
> +LIB_EXPORT bool l_key_verify(struct l_key *key, const void *data,
> +				const void *sig, size_t len_data,
> +				size_t len_sig)
> +{
> +	long result;
> +
> +	if (unlikely(!key))
> +		return false;
> +
> +	result = kernel_key_verify(key->serial, key->encoding, key->hash,
> +					data, sig, len_data, len_sig);
> +
> +	return result == 0;
> +}
> +
>   LIB_EXPORT struct l_keyring *l_keyring_new(enum l_keyring_type type,
>   						const struct l_keyring *trusted)
>   {
> diff --git a/ell/key.h b/ell/key.h
> index 5d981f1..f5176d1 100644
> --- a/ell/key.h
> +++ b/ell/key.h
> @@ -30,6 +30,9 @@ extern "C" {
>   #include <stddef.h>
>   #include <stdbool.h>
>
> +#include <ell/checksum.h>
> +#include <ell/cipher.h>
> +
>   struct l_key;
>   struct l_keyring;
>
> @@ -54,12 +57,30 @@ bool l_key_extract(struct l_key *key, void *payload, size_t *len);
>
>   ssize_t l_key_get_size(struct l_key *key);
>
> +bool l_key_get_info(struct l_key *key, size_t *bits, bool *public);
> +
>   bool l_key_compute_dh_public(struct l_key *generator, struct l_key *private,
>   			     struct l_key *prime, void *payload, size_t *len);
>
>   bool l_key_compute_dh_secret(struct l_key *other_public, struct l_key *private,
>   			     struct l_key *prime, void *payload, size_t *len);
>
> +bool l_key_set_cipher(struct l_key *key, enum l_asymmetric_cipher_type cipher);
> +
> +bool l_key_set_checksum_info(struct l_key *key, enum l_checksum_type checksum);
> +

Why not make these parameters into encrypt / decrypt / sign / verify 
operation?

> +ssize_t l_key_encrypt(struct l_key *key, const void *in, void *out,
> +			size_t len_in, size_t len_out);
> +
> +ssize_t l_key_decrypt(struct l_key *key, const void *in, void *out,
> +			size_t len_in, size_t len_out);
> +
> +ssize_t l_key_sign(struct l_key *key, const void *in, void *out,
> +			size_t len_in, size_t len_out);
> +
> +bool l_key_verify(struct l_key *key, const void *data, const void *sig,
> +			size_t len_data, size_t len_sig);
> +
>   struct l_keyring *l_keyring_new(enum l_keyring_type type,
>   				const struct l_keyring *trust);
>
>

Regards,
-Denis

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 3/4] key: Add key-based asymmetric crypto operations
  2016-07-22 19:35   ` Denis Kenzior
@ 2016-07-22 21:55     ` Mat Martineau
  0 siblings, 0 replies; 9+ messages in thread
From: Mat Martineau @ 2016-07-22 21:55 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 10414 bytes --]

On Fri, 22 Jul 2016, Denis Kenzior wrote:

> Hi Mat,
>
> On 07/20/2016 05:19 PM, Mat Martineau wrote:
>> The kernel (as of v4.8) has asymmetric crypto methods available using
>> the keyctl API which make use of the kernel keyrings. The main
>> advantage of this API over AF_ALG is that typical asymmetric
>> operations involve fewer system calls.
>> ---
>>   ell/key.c | 200 
>> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>   ell/key.h |  21 +++++++
>>   2 files changed, 221 insertions(+)
>> 
>> diff --git a/ell/key.c b/ell/key.c
>> index 60602f9..85e461f 100644
>> --- a/ell/key.c
>> +++ b/ell/key.c
>> @@ -29,10 +29,12 @@
>>   #include <stdint.h>
>>   #include <sys/syscall.h>
>>   #include <linux/keyctl.h>
>> +#include <errno.h>
>>
>>   #include "private.h"
>>   #include "util.h"
>>   #include "key.h"
>> +#include "string.h"
>>
>>   #ifndef KEYCTL_DH_COMPUTE
>>   #define KEYCTL_DH_COMPUTE 23
>> @@ -44,11 +46,47 @@ struct keyctl_dh_params {
>>   };
>>   #endif
>> 
>> +#ifndef KEYCTL_PKEY_QUERY
>> +#define KEYCTL_PKEY_QUERY	24
>> +#define KEYCTL_PKEY_ENCRYPT	25
>> +#define KEYCTL_PKEY_DECRYPT	26
>> +#define KEYCTL_PKEY_SIGN	27
>> +#define KEYCTL_PKEY_VERIFY	28
>> +
>> +#define KEYCTL_SUPPORTS_ENCRYPT	0x01
>> +#define KEYCTL_SUPPORTS_DECRYPT	0x02
>> +#define KEYCTL_SUPPORTS_SIGN	0x04
>> +#define KEYCTL_SUPPORTS_VERIFY	0x08
>> +
>> +struct keyctl_pkey_query {
>> +	uint32_t supported_ops;
>> +	uint32_t key_size;
>> +	uint16_t max_data_size;
>> +	uint16_t max_sig_size;
>> +	uint16_t max_enc_size;
>> +	uint16_t max_dec_size;
>> +
>> +	uint32_t __spare[10];
>> +};
>> +
>> +struct keyctl_pkey_params {
>> +	int32_t key_id;
>> +	uint32_t in_len;
>> +	union {
>> +		uint32_t out_len;
>> +		uint32_t in2_len;
>> +	};
>> +	uint32_t __spare[7];
>> +};
>> +#endif
>> +
>>   static int32_t internal_keyring;
>>
>>   struct l_key {
>>   	int type;
>>   	int32_t serial;
>> +	char *encoding;
>> +	char *hash;
>
> Should these be const char?

I think I'll take these out and rely on parameters to the crypto functions 
instead.

>
>>   };
>>
>>   struct l_keyring {
>> @@ -117,6 +155,43 @@ static long kernel_unlink_key(int32_t key_serial, 
>> int32_t ring_serial)
>>   	return result >= 0 ? result : -errno;
>>   }
>> 
>> +static char *format_key_info(const char *encoding, const char *hash)
>> +{
>> +	struct l_string *info;
>> +
>> +	if (!encoding && !hash)
>> +		return NULL;
>> +
>> +	info = l_string_new(0);
>> +
>> +	if (encoding)
>> +		l_string_append_printf(info, "enc=%s ", encoding);
>> +
>> +	if (hash)
>> +		l_string_append_printf(info, "hash=%s", hash);
>> +
>> +	return l_string_free(info, false);
>> +}
>> +
>> +static long kernel_query_key(int32_t key_serial, size_t *size, bool 
>> *public,
>> +				const char *encoding, const char *hash)
>> +{
>> +	long result;
>> +	struct keyctl_pkey_query query;
>> +	char *info = format_key_info(encoding, hash);
>> +
>> +	result = syscall(__NR_keyctl, KEYCTL_PKEY_QUERY, key_serial, 0,
>> +				info ?: "", &query);
>> +	if (result == 0) {
>> +		*size = query.key_size;
>> +		*public = ((query.supported_ops & KEYCTL_SUPPORTS_ENCRYPT) &&
>> +			!(query.supported_ops & KEYCTL_SUPPORTS_DECRYPT));
>> +	}
>> +	l_free(info);
>> +
>> +	return result >= 0 ? result : -errno;
>> +}
>> +
>>   static long kernel_dh_compute(int32_t private, int32_t prime, int32_t 
>> base,
>>   			      void *payload, size_t len)
>>   {
>> @@ -132,6 +207,40 @@ static long kernel_dh_compute(int32_t private, int32_t 
>> prime, int32_t base,
>>   	return result >= 0 ? result : -errno;
>>   }
>> 
>> +static long kernel_key_eds(int op, int32_t serial, const char *encoding,
>> +				const char *hash, const void *in, void *out,
>> +				size_t len_in, size_t len_out)
>> +{
>> +	long result;
>> +	struct keyctl_pkey_params params = { .key_id = serial,
>> +					     .in_len = len_in,
>> +					     .out_len = len_out };
>> +	char *info = format_key_info(encoding, hash);
>> +
>> +	result = syscall(__NR_keyctl, op, &params, info ?: "", in, out);
>> +	l_free(info);
>> +
>> +	return result >= 0 ? result : -errno;
>> +}
>> +
>> +static long kernel_key_verify(int32_t serial, const char *encoding,
>> +				const char *hash, const void *data,
>> +				const void *sig, size_t len_data,
>> +				size_t len_sig)
>> +{
>> +	long result;
>> +	struct keyctl_pkey_params params = { .key_id = serial,
>> +					     .in_len = len_data,
>> +					     .in2_len = len_sig };
>> +	char *info = format_key_info(encoding, hash);
>> +
>> +	result = syscall(__NR_keyctl, KEYCTL_PKEY_VERIFY, &params, info ?: 
>> "",
>> +				data, sig);
>> +	l_free(info);
>> +
>> +	return result >= 0 ? result : -errno;
>> +}
>> +
>>   static bool setup_internal_keyring(void)
>>   {
>>   	internal_keyring = kernel_add_key("keyring", "ell-internal", NULL, 0,
>> @@ -220,6 +329,12 @@ LIB_EXPORT ssize_t l_key_get_size(struct l_key *key)
>>   	return kernel_read_key(key->serial, NULL, 0);
>>   }
>> 
>> +bool l_key_get_info(struct l_key *key, size_t *bits, bool *public)
>> +{
>> +	return !kernel_query_key(key->serial, bits, public, key->encoding,
>> +					key->hash);
>> +}
>> +
>
> How is this related to l_key_get_size()?

This function is only applicable to asymmetric keys and returns the bit 
length of the modulus.

l_key_get_size() is the number of bytes you'd need to store the payload 
returned by l_key_extract(). And l_key_extract() doesn't work with 
asymmetric keys...

I'm not sure l_key_get_size() is worth keeping around. l_key_extract() 
could do the job if *len == 0.

>
> We might want to start documenting the l_key methods...

Yes, more documentation is in order.

>
>>   static bool compute_common(struct l_key *base,
>>   			   struct l_key *private,
>>   			   struct l_key *prime,
>> @@ -255,6 +370,91 @@ LIB_EXPORT bool l_key_compute_dh_secret(struct l_key 
>> *other_public,
>>   	return compute_common(other_public, private, prime, payload, len);
>>   }
>> 
>> +LIB_EXPORT bool l_key_set_cipher(struct l_key *key,
>> +					enum l_asymmetric_cipher_type cipher)
>> +{
>> +	if (unlikely(!key))
>> +		return false;
>> +
>> +	switch (cipher) {
>> +	case L_CIPHER_RSA_PKCS1_V1_5:
>> +		key->encoding = "pkcs1";
>> +		break;
>> +	}
>> +
>> +	return true;
>> +}
>> +
>> +LIB_EXPORT bool l_key_set_checksum_info(struct l_key *key,
>> +					enum l_checksum_type checksum)
>> +{
>> +	if (unlikely(!key))
>> +		return false;
>> +
>> +	switch (checksum) {
>> +	case L_CHECKSUM_MD5:
>> +		key->hash = "md5";
>> +		break;
>> +	case L_CHECKSUM_SHA1:
>> +		key->hash = "sha1";
>> +		break;
>> +	case L_CHECKSUM_SHA256:
>> +		key->hash = "sha256";
>> +		break;
>> +	case L_CHECKSUM_SHA384:
>> +		key->hash = "sha384";
>> +		break;
>> +	case L_CHECKSUM_SHA512:
>> +		key->hash = "sha512";
>> +		break;
>> +	}
>> +
>> +	return true;
>> +}
>> +
>> +static ssize_t eds_common(struct l_key *key, const void *in, void *out,
>> +				size_t len_in, size_t len_out, int op)
>
> Whats eds stand for?

encrypt/decrypt/sign

>
>> +{
>> +	if (unlikely(!key))
>> +		return -EINVAL;
>> +
>> +	return kernel_key_eds(op, key->serial, key->encoding, key->hash, in,
>> +				out, len_in, len_out);
>> +}
>> +
>> +LIB_EXPORT ssize_t l_key_encrypt(struct l_key *key, const void *in, void 
>> *out,
>> +			size_t len_in, size_t len_out)
>> +{
>> +	return eds_common(key, in, out, len_in, len_out, 
>> KEYCTL_PKEY_ENCRYPT);
>> +}
>> +
>> +LIB_EXPORT ssize_t l_key_decrypt(struct l_key *key, const void *in, void 
>> *out,
>> +			size_t len_in, size_t len_out)
>> +{
>> +	return eds_common(key, in, out, len_in, len_out, 
>> KEYCTL_PKEY_DECRYPT);
>> +}
>> +
>> +LIB_EXPORT ssize_t l_key_sign(struct l_key *key, const void *in, void 
>> *out,
>> +			size_t len_in, size_t len_out)
>> +{
>> +	return eds_common(key, in, out, len_in, len_out, KEYCTL_PKEY_SIGN);
>> +}
>> +
>> +LIB_EXPORT bool l_key_verify(struct l_key *key, const void *data,
>> +				const void *sig, size_t len_data,
>> +				size_t len_sig)
>> +{
>> +	long result;
>> +
>> +	if (unlikely(!key))
>> +		return false;
>> +
>> +	result = kernel_key_verify(key->serial, key->encoding, key->hash,
>> +					data, sig, len_data, len_sig);
>> +
>> +	return result == 0;
>> +}
>> +
>>   LIB_EXPORT struct l_keyring *l_keyring_new(enum l_keyring_type type,
>>   						const struct l_keyring 
>> *trusted)
>>   {
>> diff --git a/ell/key.h b/ell/key.h
>> index 5d981f1..f5176d1 100644
>> --- a/ell/key.h
>> +++ b/ell/key.h
>> @@ -30,6 +30,9 @@ extern "C" {
>>   #include <stddef.h>
>>   #include <stdbool.h>
>> 
>> +#include <ell/checksum.h>
>> +#include <ell/cipher.h>
>> +
>>   struct l_key;
>>   struct l_keyring;
>> 
>> @@ -54,12 +57,30 @@ bool l_key_extract(struct l_key *key, void *payload, 
>> size_t *len);
>>
>>   ssize_t l_key_get_size(struct l_key *key);
>> 
>> +bool l_key_get_info(struct l_key *key, size_t *bits, bool *public);
>> +
>>   bool l_key_compute_dh_public(struct l_key *generator, struct l_key 
>> *private,
>>   			     struct l_key *prime, void *payload, size_t 
>> *len);
>>
>>   bool l_key_compute_dh_secret(struct l_key *other_public, struct l_key 
>> *private,
>>   			     struct l_key *prime, void *payload, size_t 
>> *len);
>> 
>> +bool l_key_set_cipher(struct l_key *key, enum l_asymmetric_cipher_type 
>> cipher);
>> +
>> +bool l_key_set_checksum_info(struct l_key *key, enum l_checksum_type 
>> checksum);
>> +
>
> Why not make these parameters into encrypt / decrypt / sign / verify 
> operation?

I think that would work better.

>
>> +ssize_t l_key_encrypt(struct l_key *key, const void *in, void *out,
>> +			size_t len_in, size_t len_out);
>> +
>> +ssize_t l_key_decrypt(struct l_key *key, const void *in, void *out,
>> +			size_t len_in, size_t len_out);
>> +
>> +ssize_t l_key_sign(struct l_key *key, const void *in, void *out,
>> +			size_t len_in, size_t len_out);
>> +
>> +bool l_key_verify(struct l_key *key, const void *data, const void *sig,
>> +			size_t len_data, size_t len_sig);
>> +
>>   struct l_keyring *l_keyring_new(enum l_keyring_type type,
>>   				const struct l_keyring *trust);
>> 
>>

--
Mat Martineau
Intel OTC

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2016-07-22 21:55 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-20 22:19 [PATCH 1/4] key: Update restrict method name Mat Martineau
2016-07-20 22:19 ` [PATCH 2/4] key: Consistently return errno from syscall wrappers Mat Martineau
2016-07-21 20:19   ` Denis Kenzior
2016-07-21 21:23     ` Mat Martineau
2016-07-20 22:19 ` [PATCH 3/4] key: Add key-based asymmetric crypto operations Mat Martineau
2016-07-22 19:35   ` Denis Kenzior
2016-07-22 21:55     ` Mat Martineau
2016-07-20 22:19 ` [PATCH 4/4] unit: Add tests for key-based asymmetric crypto Mat Martineau
2016-07-21 20:19 ` [PATCH 1/4] key: Update restrict method name Denis Kenzior

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.