Skip to contentSkip to conversation

crypto: add ECDSA signature support to key retention service

PATCH Superseded Ignat Korchagin 2 participants 8 messages Sep 8, 2022 – Sep 28, 2022

Subsystems (4)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

cover crypto: add ECDSA signature support to key retention service

Kernel Key Retention Service[1] is a useful building block to build secure production key management systems. One of its interesting features is support for asymmetric keys: we can allow a process to use a certain key (decrypt or sign data) without actually allowing the process to read the cryptographic key material. By doing so we protect our code from certain type of attacks, where a process memory memory leak actually leaks a potentially highly sensitive cryptographic material.

But unfortunately only RSA algorithm was supported until now, because in-kernel ECDSA implementation supported signature verifications only.

This patchset implements in-kernel ECDSA signature generation and adds support for ECDSA signing in the key retention service. The key retention service support was taken out of a previous unmerged patchset from Lei He[2]

[1]: https://www.kernel.org/doc/html/latest/security/keys/core.html
[2]: https://patchwork.kernel.org/project/linux-crypto/list/?series=653034&state=*

Ignat Korchagin (2):
crypto: add ECDSA signature generation support
crypto: add ECDSA test vectors from RFC 6979

lei he (2):
crypto: pkcs8 parser support ECDSA private keys
crypto: remove unused field in pkcs8_parse_context

 crypto/Kconfig                        |   3 +-
 crypto/Makefile                       |   4 +-
 crypto/asymmetric_keys/pkcs8.asn1     |   2 +-
 crypto/asymmetric_keys/pkcs8_parser.c |  46 +++-
 crypto/ecc.c                          |   9 +-
 crypto/ecdsa.c                        | 373 +++++++++++++++++++++++++-
 crypto/ecprivkey.asn1                 |   6 +
 crypto/testmgr.c                      |  18 ++
 crypto/testmgr.h                      | 333 +++++++++++++++++++++++
 include/crypto/internal/ecc.h         |  11 +
 10 files changed, 788 insertions(+), 17 deletions(-)
 create mode 100644 crypto/ecprivkey.asn1

--
2.36.1

#1 lore raw

PATCH 1/4 crypto: add ECDSA signature generation support

Add ECDSA signature generation support to reach feature parity with RSA and make it possible later to use ECDSA via asymmetric key support in keyctl.

This code implements deterministic ECDSA from RFC 6979[1]. This has the following advantages:
* we can more easily test the implementation with KAT test vectors
* on platforms with bad/limited entropy generation capabilities the generated signatures would still be secure

Probably, the disadvantage is that ECDSA now depends on CRYPTO_DRBG, which is mostly enabled anyway.

[1]: https://datatracker.ietf.org/doc/html/rfc6979

---
 crypto/Kconfig                |   3 +-
 crypto/Makefile               |   4 +-
 crypto/ecc.c                  |   9 +-
 crypto/ecdsa.c                | 373 +++++++++++++++++++++++++++++++++-
 crypto/ecprivkey.asn1         |   6 +
 include/crypto/internal/ecc.h |  11 +
 6 files changed, 394 insertions(+), 12 deletions(-)
 create mode 100644 crypto/ecprivkey.asn1
crypto/Kconfig +1 -2
index 40423a14f86f..ae2c9c48d751 100644
@@ -285,14 +285,13 @@ config CRYPTO_ECDSA
 	tristate "ECDSA (Elliptic Curve Digital Signature Algorithm)"
 	select CRYPTO_ECC
 	select CRYPTO_AKCIPHER
+	select CRYPTO_DRBG_HMAC
 	select ASN1
 	help
 	  ECDSA (Elliptic Curve Digital Signature Algorithm) (FIPS 186,
 	  ISO/IEC 14888-3)
 	  using curves P-192, P-256, and P-384
 
-	  Only signature verification is implemented.
-
 config CRYPTO_ECRDSA
 	tristate "EC-RDSA (Elliptic Curve Russian Digital Signature Algorithm)"
 	select CRYPTO_ECC
crypto/Makefile +3 -1
index a6f94e04e1da..3f7578790594 100644
@@ -50,9 +50,11 @@ sm2_generic-y += sm2.o
 
 obj-$(CONFIG_CRYPTO_SM2) += sm2_generic.o
 
+$(obj)/ecprivkey.asn1.o: $(obj)/ecprivkey.asn1.c $(obj)/ecprivkey.asn1.h
 $(obj)/ecdsasignature.asn1.o: $(obj)/ecdsasignature.asn1.c $(obj)/ecdsasignature.asn1.h
-$(obj)/ecdsa.o: $(obj)/ecdsasignature.asn1.h
+$(obj)/ecdsa.o: $(obj)/ecdsasignature.asn1.h $(obj)/ecprivkey.asn1.h
 ecdsa_generic-y += ecdsa.o
+ecdsa_generic-y += ecprivkey.asn1.o
 ecdsa_generic-y += ecdsasignature.asn1.o
 obj-$(CONFIG_CRYPTO_ECDSA) += ecdsa_generic.o
 
crypto/ecc.c +6 -3
index 7315217c8f73..e2a111e00eea 100644
@@ -488,7 +488,7 @@ static void vli_square(u64 *result, const u64 *left, unsigned int ndigits)
 /* Computes result = (left + right) % mod.
  * Assumes that left < mod and right < mod, result != mod.
  */
-static void vli_mod_add(u64 *result, const u64 *left, const u64 *right,
+void vli_mod_add(u64 *result, const u64 *left, const u64 *right,
 			const u64 *mod, unsigned int ndigits)
 {
 	u64 carry;
@@ -501,6 +501,7 @@ static void vli_mod_add(u64 *result, const u64 *left, const u64 *right,
 	if (carry || vli_cmp(result, mod, ndigits) >= 0)
 		vli_sub(result, result, mod, ndigits);
 }
+EXPORT_SYMBOL(vli_mod_add);
 
 /* Computes result = (left - right) % mod.
  * Assumes that left < mod and right < mod, result != mod.
@@ -963,7 +964,7 @@ void vli_mod_mult_slow(u64 *result, const u64 *left, const u64 *right,
 EXPORT_SYMBOL(vli_mod_mult_slow);
 
 /* Computes result = (left * right) % curve_prime. */
-static void vli_mod_mult_fast(u64 *result, const u64 *left, const u64 *right,
+void vli_mod_mult_fast(u64 *result, const u64 *left, const u64 *right,
 			      const struct ecc_curve *curve)
 {
 	u64 product[2 * ECC_MAX_DIGITS];
@@ -971,6 +972,7 @@ static void vli_mod_mult_fast(u64 *result, const u64 *left, const u64 *right,
 	vli_mult(product, left, right, curve->g.ndigits);
 	vli_mmod_fast(result, product, curve);
 }
+EXPORT_SYMBOL(vli_mod_mult_fast);
 
 /* Computes result = left^2 % curve_prime. */
 static void vli_mod_square_fast(u64 *result, const u64 *left,
@@ -1277,7 +1279,7 @@ static void xycz_add_c(u64 *x1, u64 *y1, u64 *x2, u64 *y2,
 	vli_set(x1, t7, ndigits);
 }
 
-static void ecc_point_mult(struct ecc_point *result,
+void ecc_point_mult(struct ecc_point *result,
 			   const struct ecc_point *point, const u64 *scalar,
 			   u64 *initial_z, const struct ecc_curve *curve,
 			   unsigned int ndigits)
@@ -1335,6 +1337,7 @@ static void ecc_point_mult(struct ecc_point *result,
 	vli_set(result->x, rx[0], ndigits);
 	vli_set(result->y, ry[0], ndigits);
 }
+EXPORT_SYMBOL(ecc_point_mult);
 
 /* Computes R = P + Q mod p */
 static void ecc_point_add(const struct ecc_point *result,
crypto/ecdsa.c +367 -6

438 lines not on this page · raw message

crypto/ecprivkey.asn1 new file +6 -0
new file mode 100644
index 000000000000..92e7d7d0703c
@@ -0,0 +1,6 @@
+ECPrivateKey ::= SEQUENCE {
+	version	INTEGER ({ ecc_get_priv_version }),
+	privateKey	OCTET STRING ({ ecc_get_priv_key }),
+	parameters	[0] OBJECT IDENTIFIER OPTIONAL ({ ecc_get_priv_params }),
+	publicKey	[1] BIT STRING OPTIONAL
+}
include/crypto/internal/ecc.h +11 -0
index 4f6c1a68882f..be03a48302e5 100644
@@ -182,6 +182,9 @@ int vli_cmp(const u64 *left, const u64 *right, unsigned int ndigits);
 u64 vli_sub(u64 *result, const u64 *left, const u64 *right,
 	    unsigned int ndigits);
 
+void vli_mod_add(u64 *result, const u64 *left, const u64 *right,
+			const u64 *mod, unsigned int ndigits);
+
 /**
  * vli_from_be64() - Load vli from big-endian u64 array
  *
@@ -225,6 +228,9 @@ void vli_mod_inv(u64 *result, const u64 *input, const u64 *mod,
 void vli_mod_mult_slow(u64 *result, const u64 *left, const u64 *right,
 		       const u64 *mod, unsigned int ndigits);
 
+void vli_mod_mult_fast(u64 *result, const u64 *left, const u64 *right,
+			      const struct ecc_curve *curve);
+
 /**
  * vli_num_bits() - Counts the number of bits required for vli.
  *
@@ -260,6 +266,11 @@ void ecc_free_point(struct ecc_point *p);
  */
 bool ecc_point_is_zero(const struct ecc_point *point);
 
+void ecc_point_mult(struct ecc_point *result,
+			   const struct ecc_point *point, const u64 *scalar,
+			   u64 *initial_z, const struct ecc_curve *curve,
+			   unsigned int ndigits);
+
 /**
  * ecc_point_mult_shamir() - Add two points multiplied by scalars
  *

--
2.36.1

#2 lore raw

PATCH 2/4 crypto: add ECDSA test vectors from RFC 6979

In reply to Ignat Korchagin

These test vectors are for testing deterministic ECDSA signature generation. We explicitly bind the tests to the in-kernel generic ECDSA driver as other drivers may not implement deterministic ECDSA, so cannot use KAT type tests.

---
 crypto/testmgr.c |  18 +++
 crypto/testmgr.h | 333 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 351 insertions(+)
crypto/testmgr.c +18 -0
index e4bb03b8b924..1e479ab971fc 100644
@@ -5026,18 +5026,36 @@ static const struct alg_test_desc alg_test_descs[] = {
 		.suite = {
 			.akcipher = __VECS(ecdsa_nist_p192_tv_template)
 		}
+	}, {
+		.alg = "ecdsa-nist-p192-generic",
+		.test = alg_test_akcipher,
+		.suite = {
+			.akcipher = __VECS(ecdsa_nist_p192_rfc6979_tv_template)
+		}
 	}, {
 		.alg = "ecdsa-nist-p256",
 		.test = alg_test_akcipher,
 		.suite = {
 			.akcipher = __VECS(ecdsa_nist_p256_tv_template)
 		}
+	}, {
+		.alg = "ecdsa-nist-p256-generic",
+		.test = alg_test_akcipher,
+		.suite = {
+			.akcipher = __VECS(ecdsa_nist_p256_rfc6979_tv_template)
+		}
 	}, {
 		.alg = "ecdsa-nist-p384",
 		.test = alg_test_akcipher,
 		.suite = {
 			.akcipher = __VECS(ecdsa_nist_p384_tv_template)
 		}
+	}, {
+		.alg = "ecdsa-nist-p384-generic",
+		.test = alg_test_akcipher,
+		.suite = {
+			.akcipher = __VECS(ecdsa_nist_p384_rfc6979_tv_template)
+		}
 	}, {
 		.alg = "ecrdsa",
 		.test = alg_test_akcipher,
crypto/testmgr.h +333 -0

339 lines not on this page · raw message

--
2.36.1

#3 lore raw

PATCH 3/4 crypto: pkcs8 parser support ECDSA private keys

In reply to Ignat Korchagin

From: lei he <[email protected]>

Make pkcs8_private_key_parser can identify ECDSA private keys.

---
 crypto/asymmetric_keys/pkcs8.asn1     |  2 +-
 crypto/asymmetric_keys/pkcs8_parser.c | 45 +++++++++++++++++++++++++--
 2 files changed, 43 insertions(+), 4 deletions(-)
crypto/asymmetric_keys/pkcs8.asn1 +1 -1
index 702c41a3c713..1791ddf4168a 100644
@@ -20,5 +20,5 @@ Attribute ::= ANY
 
 AlgorithmIdentifier ::= SEQUENCE {
 	algorithm   OBJECT IDENTIFIER ({ pkcs8_note_OID }),
-	parameters  ANY OPTIONAL
+	parameters  ANY OPTIONAL ({ pkcs8_note_algo_parameter })
 }
crypto/asymmetric_keys/pkcs8_parser.c +42 -3

65 lines not on this page · raw message

--
2.36.1

#4 lore raw

PATCH 4/4 crypto: remove unused field in pkcs8_parse_context

In reply to Ignat Korchagin

From: lei he <[email protected]>

remove unused field 'algo_oid' in pkcs8_parse_context

---
 crypto/asymmetric_keys/pkcs8_parser.c | 1 -
 1 file changed, 1 deletion(-)
crypto/asymmetric_keys/pkcs8_parser.c +0 -1
index e507c635ead5..f81317234331 100644
@@ -21,7 +21,6 @@ struct pkcs8_parse_context {
 	struct public_key *pub;
 	unsigned long	data;			/* Start of data */
 	enum OID	last_oid;		/* Last OID encountered */
-	enum OID	algo_oid;		/* Algorithm OID */
 	u32		key_size;
 	const void	*key;
 	const void	*algo_param;

--
2.36.1

maintainer
#5 lore raw
In reply to Ignat Korchagin
Quoted 39 lines · Ignat Korchagin

Kernel Key Retention Service[1] is a useful building block to build secure production key management systems. One of its interesting features is support for asymmetric keys: we can allow a process to use a certain key (decrypt or sign data) without actually allowing the process to read the cryptographic key material. By doing so we protect our code from certain type of attacks, where a process memory memory leak actually leaks a potentially highly sensitive cryptographic material.

But unfortunately only RSA algorithm was supported until now, because in-kernel ECDSA implementation supported signature verifications only.

This patchset implements in-kernel ECDSA signature generation and adds support for ECDSA signing in the key retention service. The key retention service support was taken out of a previous unmerged patchset from Lei He[2]

[1]: https://www.kernel.org/doc/html/latest/security/keys/core.html
[2]: https://patchwork.kernel.org/project/linux-crypto/list/?series=653034&state=*

Ignat Korchagin (2):
crypto: add ECDSA signature generation support
crypto: add ECDSA test vectors from RFC 6979

lei he (2):
crypto: pkcs8 parser support ECDSA private keys
crypto: remove unused field in pkcs8_parse_context

 crypto/Kconfig                        |   3 +-
 crypto/Makefile                       |   4 +-
 crypto/asymmetric_keys/pkcs8.asn1     |   2 +-
 crypto/asymmetric_keys/pkcs8_parser.c |  46 +++-
 crypto/ecc.c                          |   9 +-
 crypto/ecdsa.c                        | 373 +++++++++++++++++++++++++-
 crypto/ecprivkey.asn1                 |   6 +
 crypto/testmgr.c                      |  18 ++
 crypto/testmgr.h                      | 333 +++++++++++++++++++++++
 include/crypto/internal/ecc.h         |  11 +
 10 files changed, 788 insertions(+), 17 deletions(-)
 create mode 100644 crypto/ecprivkey.asn1
Quoted 2 lines

--
2.36.1

I need acks for patches 3-4 from David. Thanks!

Signature · 3 lines
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
#6 lore raw
Quoted 41 lines · Herbert Xu
Quoted 39 lines · Ignat Korchagin

Kernel Key Retention Service[1] is a useful building block to build secure production key management systems. One of its interesting features is support for asymmetric keys: we can allow a process to use a certain key (decrypt or sign data) without actually allowing the process to read the cryptographic key material. By doing so we protect our code from certain type of attacks, where a process memory memory leak actually leaks a potentially highly sensitive cryptographic material.

But unfortunately only RSA algorithm was supported until now, because in-kernel ECDSA implementation supported signature verifications only.

This patchset implements in-kernel ECDSA signature generation and adds support for ECDSA signing in the key retention service. The key retention service support was taken out of a previous unmerged patchset from Lei He[2]

[1]: https://www.kernel.org/doc/html/latest/security/keys/core.html
[2]: https://patchwork.kernel.org/project/linux-crypto/list/?series=653034&state=*

Ignat Korchagin (2):
crypto: add ECDSA signature generation support
crypto: add ECDSA test vectors from RFC 6979

lei he (2):
crypto: pkcs8 parser support ECDSA private keys
crypto: remove unused field in pkcs8_parse_context

 crypto/Kconfig                        |   3 +-
 crypto/Makefile                       |   4 +-
 crypto/asymmetric_keys/pkcs8.asn1     |   2 +-
 crypto/asymmetric_keys/pkcs8_parser.c |  46 +++-
 crypto/ecc.c                          |   9 +-
 crypto/ecdsa.c                        | 373 +++++++++++++++++++++++++-
 crypto/ecprivkey.asn1                 |   6 +
 crypto/testmgr.c                      |  18 ++
 crypto/testmgr.h                      | 333 +++++++++++++++++++++++
 include/crypto/internal/ecc.h         |  11 +
 10 files changed, 788 insertions(+), 17 deletions(-)
 create mode 100644 crypto/ecprivkey.asn1
Quoted 4 lines
Quoted 2 lines

--
2.36.1

I need acks for patches 3-4 from David. Thanks!

Should I resend patches 1-2 here and maybe 3-4 to the linux-keyrings mailing list?

Quoted 3 lines

Email: Herbert Xu <[email protected]> Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

Ignat

maintainer
#7 lore raw

On Tue, Sep 27, 2022 at 10:18:14PM +0100, Ignat Korchagin wrote:
.

Quoted 2 lines

Should I resend patches 1-2 here and maybe 3-4 to the linux-keyrings mailing list?

I need acks to patches 3-4 because without a user we don't add new algorithms to the Crypto API.

Thanks,

Signature · 3 lines
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt