2021-10-12 02:19:45

by Hongbo Li

[permalink] [raw]
Subject: [PATCH v3 0/5] crypto: add eddsa support for x509

This series of patches add support for x509 cert signed by eddsa,
which is described in RFC8032 [1], currently ed25519 only.

Curve25519 is an elliptic curve used for key agreement(ECDH).
It is a Montgomery curve.

Edwards25519 is a twisted Edwards curve and birationally equivalent
to Curve25519, the birational maps are described in rfc7748 section 4.1.[2]
Ed25519 is a Digital Signature Algorithm over Edwards25519.

The kernel's curve25519 code is used for ECDH, such as set_secret(),
generate_public_key() and compute_shared_secret(), these are useless
for eddsa, and can not be reused, eddsa do the verification on the
given public key and signature.

According to RFC8032 section 4 [3], there're two variants: PureEdDSA and
HashEdDSA. These patches support PureEdDSA which named Ed25519.

Patch1 exports some mpi common functions.

Patch2 makes x509 layer support eddsa.

Patch3 moves some common code in sm2 to separate files. These code is also
used by eddsa.

Patch4 is the implementation of eddsa verification according to RFC8032
section 5.1.7 [4].

Patch5 adds test vector for eddsa.

Test by the following script:

keyctl newring test @u

while :; do
certfile="cert.der"

openssl req \
-x509 \
-newkey ED25519 \
-keyout key.pem \
-days 365 \
-subj '/CN=test' \
-nodes \
-outform der \
-out ${certfile} 2>/dev/null

exp=0
id=$(keyctl padd asymmetric testkey %keyring:test < "${certfile}")
rc=$?
if [ $rc -ne $exp ]; then
case "$exp" in
0) echo "Error: Could not load ed25519 certificate $certfile!";
esac
exit 1
else
case "$rc" in
0) printf "load ed25519 cert keyid: %-10s\n" $id;
esac
fi
done

Best Regards
Hongbo

[1] https://datatracker.ietf.org/doc/html/rfc8032
[2] https://datatracker.ietf.org/doc/html/rfc7748#section-4.1
[3] https://datatracker.ietf.org/doc/html/rfc8032#section-4
[4] https://datatracker.ietf.org/doc/html/rfc8032#section-5.1.7

v1->v2:
-fix the warning "warning: no previous prototype"
reported-by: kernel test robot <[email protected]>
-add more comments about these patches

v2->v3:
-remove the v2-0001-crypto-fix-a-memory-leak-in-sm2.patch and
v2-0002-lib-mpi-use-kcalloc-in-mpi_resize.patch from patch series,
because they have been merged into kernel.

Hongbo Li (5):
lib/mpi: export some common function
x509: add support for eddsa
crypto: move common code in sm2 to ec_mpi.c and ec_mpi.h
crypto: ed25519 cert verification
crypto: add eddsa test vector

crypto/Kconfig | 15 ++
crypto/Makefile | 4 +
crypto/asymmetric_keys/public_key.c | 73 ++++++-
crypto/asymmetric_keys/x509_cert_parser.c | 14 +-
crypto/asymmetric_keys/x509_public_key.c | 4 +-
crypto/ec_mpi.c | 82 ++++++++
crypto/ec_mpi.h | 37 ++++
crypto/eddsa.c | 326 ++++++++++++++++++++++++++++++
crypto/sm2.c | 98 +--------
crypto/testmgr.c | 6 +
crypto/testmgr.h | 32 +++
include/linux/oid_registry.h | 1 +
lib/mpi/mpi-add.c | 4 +-
13 files changed, 589 insertions(+), 107 deletions(-)
create mode 100644 crypto/ec_mpi.c
create mode 100644 crypto/ec_mpi.h
create mode 100644 crypto/eddsa.c

--
1.8.3.1


2021-10-12 02:20:06

by Hongbo Li

[permalink] [raw]
Subject: [PATCH v3 3/5] crypto: move common code in sm2 to ec_mpi.c and ec_mpi.h

From: Hongbo Li <[email protected]>

Some structs and functions in sm2 are common codes, and could be
used by the following eddsa patch. So move them to common files:
ec_mpi.c and ec_mpi.h.

Signed-off-by: Hongbo Li <[email protected]>
---
crypto/Kconfig | 4 +++
crypto/Makefile | 1 +
crypto/ec_mpi.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++
crypto/ec_mpi.h | 37 ++++++++++++++++++++++
crypto/sm2.c | 98 ++-------------------------------------------------------
5 files changed, 127 insertions(+), 95 deletions(-)
create mode 100644 crypto/ec_mpi.c
create mode 100644 crypto/ec_mpi.h

diff --git a/crypto/Kconfig b/crypto/Kconfig
index 285f826..f684513 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -265,6 +265,9 @@ config CRYPTO_ECRDSA
standard algorithms (called GOST algorithms). Only signature verification
is implemented.

+config CRYPTO_EC_MPI
+ tristate
+
config CRYPTO_SM2
tristate "SM2 algorithm"
select CRYPTO_SM3
@@ -272,6 +275,7 @@ config CRYPTO_SM2
select CRYPTO_MANAGER
select MPILIB
select ASN1
+ select CRYPTO_EC_MPI
help
Generic implementation of the SM2 public key algorithm. It was
published by State Encryption Management Bureau, China.
diff --git a/crypto/Makefile b/crypto/Makefile
index c633f15..837aa1d 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -176,6 +176,7 @@ obj-$(CONFIG_CRYPTO_OFB) += ofb.o
obj-$(CONFIG_CRYPTO_ECC) += ecc.o
obj-$(CONFIG_CRYPTO_ESSIV) += essiv.o
obj-$(CONFIG_CRYPTO_CURVE25519) += curve25519-generic.o
+obj-$(CONFIG_CRYPTO_EC_MPI) += ec_mpi.o

ecdh_generic-y += ecdh.o
ecdh_generic-y += ecdh_helper.o
diff --git a/crypto/ec_mpi.c b/crypto/ec_mpi.c
new file mode 100644
index 0000000..a537e6f
--- /dev/null
+++ b/crypto/ec_mpi.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * EC MPI common functions.
+ *
+ * Copyright (c) 2020, Alibaba Group.
+ * Authors: Tianjia Zhang <[email protected]>
+ */
+
+#include <linux/module.h>
+#include <linux/mpi.h>
+#include "ec_mpi.h"
+
+int ec_mpi_ctx_init(struct mpi_ec_ctx *ec, const struct ecc_domain_parms *ecp)
+{
+ MPI p, a, b;
+ MPI x, y;
+ int rc = -EINVAL;
+
+ p = mpi_scanval(ecp->p);
+ a = mpi_scanval(ecp->a);
+ b = mpi_scanval(ecp->b);
+ if (!p || !a || !b)
+ goto free_p;
+
+ x = mpi_scanval(ecp->g_x);
+ y = mpi_scanval(ecp->g_y);
+ if (!x || !y)
+ goto free;
+
+ rc = -ENOMEM;
+
+ ec->Q = mpi_point_new(0);
+ if (!ec->Q)
+ goto free;
+
+ /* mpi_ec_setup_elliptic_curve */
+ ec->G = mpi_point_new(0);
+ if (!ec->G) {
+ mpi_point_release(ec->Q);
+ goto free;
+ }
+
+ mpi_set(ec->G->x, x);
+ mpi_set(ec->G->y, y);
+ mpi_set_ui(ec->G->z, 1);
+
+ rc = -EINVAL;
+ ec->n = mpi_scanval(ecp->n);
+ if (!ec->n) {
+ mpi_point_release(ec->Q);
+ mpi_point_release(ec->G);
+ goto free;
+ }
+
+ ec->h = ecp->h;
+ ec->name = ecp->desc;
+ mpi_ec_init(ec, ecp->model, ecp->dialect, 0, p, a, b);
+
+ rc = 0;
+
+free:
+ mpi_free(x);
+ mpi_free(y);
+free_p:
+ mpi_free(p);
+ mpi_free(a);
+ mpi_free(b);
+
+ return rc;
+}
+EXPORT_SYMBOL(ec_mpi_ctx_init);
+
+void ec_mpi_ctx_deinit(struct mpi_ec_ctx *ec)
+{
+ mpi_ec_deinit(ec);
+
+ memset(ec, 0, sizeof(*ec));
+}
+EXPORT_SYMBOL(ec_mpi_ctx_deinit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tianjia Zhang <[email protected]>");
diff --git a/crypto/ec_mpi.h b/crypto/ec_mpi.h
new file mode 100644
index 0000000..e1f6d3aa
--- /dev/null
+++ b/crypto/ec_mpi.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * EC MPI common structs.
+ *
+ * Copyright (c) 2020, Alibaba Group.
+ * Authors: Tianjia Zhang <[email protected]>
+ */
+
+#include <linux/mpi.h>
+
+struct ecc_domain_parms {
+ const char *desc; /* Description of the curve. */
+ unsigned int nbits; /* Number of bits. */
+ unsigned int fips:1; /* True if this is a FIPS140-2 approved curve */
+
+ /* The model describing this curve. This is mainly used to select
+ * the group equation.
+ */
+ enum gcry_mpi_ec_models model;
+
+ /* The actual ECC dialect used. This is used for curve specific
+ * optimizations and to select encodings etc.
+ */
+ enum ecc_dialects dialect;
+
+ const char *p; /* The prime defining the field. */
+ const char *a, *b; /* The coefficients. For Twisted Edwards
+ * Curves b is used for d. For Montgomery
+ * Curves (a,b) has ((A-2)/4,B^-1).
+ */
+ const char *n; /* The order of the base point. */
+ const char *g_x, *g_y; /* Base point. */
+ unsigned int h; /* Cofactor. */
+};
+
+int ec_mpi_ctx_init(struct mpi_ec_ctx *ec, const struct ecc_domain_parms *ecp);
+void ec_mpi_ctx_deinit(struct mpi_ec_ctx *ec);
diff --git a/crypto/sm2.c b/crypto/sm2.c
index db8a4a2..ea1676b 100644
--- a/crypto/sm2.c
+++ b/crypto/sm2.c
@@ -9,42 +9,17 @@
*/

#include <linux/module.h>
-#include <linux/mpi.h>
#include <crypto/internal/akcipher.h>
#include <crypto/akcipher.h>
#include <crypto/hash.h>
#include <crypto/sm3_base.h>
#include <crypto/rng.h>
#include <crypto/sm2.h>
+#include "ec_mpi.h"
#include "sm2signature.asn1.h"

#define MPI_NBYTES(m) ((mpi_get_nbits(m) + 7) / 8)

-struct ecc_domain_parms {
- const char *desc; /* Description of the curve. */
- unsigned int nbits; /* Number of bits. */
- unsigned int fips:1; /* True if this is a FIPS140-2 approved curve */
-
- /* The model describing this curve. This is mainly used to select
- * the group equation.
- */
- enum gcry_mpi_ec_models model;
-
- /* The actual ECC dialect used. This is used for curve specific
- * optimizations and to select encodings etc.
- */
- enum ecc_dialects dialect;
-
- const char *p; /* The prime defining the field. */
- const char *a, *b; /* The coefficients. For Twisted Edwards
- * Curves b is used for d. For Montgomery
- * Curves (a,b) has ((A-2)/4,B^-1).
- */
- const char *n; /* The order of the base point. */
- const char *g_x, *g_y; /* Base point. */
- unsigned int h; /* Cofactor. */
-};
-
static const struct ecc_domain_parms sm2_ecp = {
.desc = "sm2p256v1",
.nbits = 256,
@@ -60,73 +35,6 @@ struct ecc_domain_parms {
.h = 1
};

-static int sm2_ec_ctx_init(struct mpi_ec_ctx *ec)
-{
- const struct ecc_domain_parms *ecp = &sm2_ecp;
- MPI p, a, b;
- MPI x, y;
- int rc = -EINVAL;
-
- p = mpi_scanval(ecp->p);
- a = mpi_scanval(ecp->a);
- b = mpi_scanval(ecp->b);
- if (!p || !a || !b)
- goto free_p;
-
- x = mpi_scanval(ecp->g_x);
- y = mpi_scanval(ecp->g_y);
- if (!x || !y)
- goto free;
-
- rc = -ENOMEM;
-
- ec->Q = mpi_point_new(0);
- if (!ec->Q)
- goto free;
-
- /* mpi_ec_setup_elliptic_curve */
- ec->G = mpi_point_new(0);
- if (!ec->G) {
- mpi_point_release(ec->Q);
- goto free;
- }
-
- mpi_set(ec->G->x, x);
- mpi_set(ec->G->y, y);
- mpi_set_ui(ec->G->z, 1);
-
- rc = -EINVAL;
- ec->n = mpi_scanval(ecp->n);
- if (!ec->n) {
- mpi_point_release(ec->Q);
- mpi_point_release(ec->G);
- goto free;
- }
-
- ec->h = ecp->h;
- ec->name = ecp->desc;
- mpi_ec_init(ec, ecp->model, ecp->dialect, 0, p, a, b);
-
- rc = 0;
-
-free:
- mpi_free(x);
- mpi_free(y);
-free_p:
- mpi_free(p);
- mpi_free(a);
- mpi_free(b);
-
- return rc;
-}
-
-static void sm2_ec_ctx_deinit(struct mpi_ec_ctx *ec)
-{
- mpi_ec_deinit(ec);
-
- memset(ec, 0, sizeof(*ec));
-}
-
/* RESULT must have been initialized and is set on success to the
* point given by VALUE.
*/
@@ -416,14 +324,14 @@ static int sm2_init_tfm(struct crypto_akcipher *tfm)
{
struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm);

- return sm2_ec_ctx_init(ec);
+ return ec_mpi_ctx_init(ec, &sm2_ecp);
}

static void sm2_exit_tfm(struct crypto_akcipher *tfm)
{
struct mpi_ec_ctx *ec = akcipher_tfm_ctx(tfm);

- sm2_ec_ctx_deinit(ec);
+ ec_mpi_ctx_deinit(ec);
}

static struct akcipher_alg sm2 = {
--
1.8.3.1

2021-10-12 02:20:13

by Hongbo Li

[permalink] [raw]
Subject: [PATCH v3 5/5] crypto: add eddsa test vector

From: Hongbo Li <[email protected]>

This patch adds the test vector for ed25519.
The test vector is from RFC8032 section 7.1 [1]

[1]https://datatracker.ietf.org/doc/html/rfc8032#section-7.1

Signed-off-by: Hongbo Li <[email protected]>
---
crypto/testmgr.c | 6 ++++++
crypto/testmgr.h | 32 ++++++++++++++++++++++++++++++++
2 files changed, 38 insertions(+)

diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 58eee8e..e795b6a 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -4968,6 +4968,12 @@ static int alg_test_null(const struct alg_test_desc *desc,
.akcipher = __VECS(ecrdsa_tv_template)
}
}, {
+ .alg = "eddsa-25519",
+ .test = alg_test_akcipher,
+ .suite = {
+ .akcipher = __VECS(eddsa_25519_tv_template)
+ }
+ }, {
.alg = "essiv(authenc(hmac(sha256),cbc(aes)),sha256)",
.test = alg_test_aead,
.fips_allowed = 1,
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index e6fca34..b5f291c 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -1145,6 +1145,38 @@ struct kpp_testvec {
};

/*
+ * EDDSA test vectors.
+ * From RFC8032 section 7.1
+ */
+static const struct akcipher_testvec eddsa_25519_tv_template[] = {
+ {
+ .key =
+ "\x3d\x40\x17\xc3\xe8\x43\x89\x5a\x92\xb7\x0a\xa7\x4d\x1b\x7e\xbc"
+ "\x9c\x98\x2c\xcf\x2e\xc4\x96\x8c\xc0\xcd\x55\xf1\x2a\xf4\x66\x0c",
+ .key_len = 32,
+ /*
+ * RFC8032 section 5.1.7. m is SHA512(dom2(F, C) || R || A || PH(M))
+ * M is 0x72
+ */
+ .m =
+ "\xa2\x71\xdf\x0d\x2b\x0d\x03\xbd\x17\xb4\xed\x9a\x4b\x6a\xfd\xdf"
+ "\x2e\x73\x28\x7f\xd6\x30\xf1\xa1\x37\xd8\x7c\xe8\x73\xa5\x91\xcc"
+ "\x31\xb6\xdd\x85\x2a\x98\xb5\xdd\x12\x26\xfe\x99\x3d\x82\x28\x27"
+ "\x8c\xeb\xa2\x1f\x80\xb8\xfc\x95\x98\x6a\x70\xd7\x1e\xdf\x3f\xaf",
+ .m_size = 64,
+ .c =
+ "\x92\xa0\x09\xa9\xf0\xd4\xca\xb8\x72\x0e\x82\x0b\x5f\x64\x25\x40"
+ "\xa2\xb2\x7b\x54\x16\x50\x3f\x8f\xb3\x76\x22\x23\xeb\xdb\x69\xda"
+ "\x08\x5a\xc1\xe4\x3e\x15\x99\x6e\x45\x8f\x36\x13\xd0\xf1\x1d\x8c"
+ "\x38\x7b\x2e\xae\xb4\x30\x2a\xee\xb0\x0d\x29\x16\x12\xbb\x0c\x00",
+ .c_size = 64,
+ .algo = OID_ed25519,
+ .public_key_vec = true,
+ .siggen_sigver_test = true,
+ }
+};
+
+/*
* PKCS#1 RSA test vectors. Obtained from CAVS testing.
*/
static const struct akcipher_testvec pkcs1pad_rsa_tv_template[] = {
--
1.8.3.1