2019-03-01 18:00:41

by Vitaly Chikunov

[permalink] [raw]
Subject: [PATCH v7 00/11] crypto: add EC-RDSA (GOST 34.10) algorithm

This patchset changes akcipher API to support ECDSA style signature
verification, augments x509 parser to make it work with EC-RDSA certificates,
and, finally, implements EC-RDSA (GOST 34.10) signature verification and its
integration with IMA.

This patchset should be applied over cryptodev commit 0918f18c7179e8cdf718d0.

Changes since (v5-v6):
- set_params API is removed in favor of appending parameters into a key stream,
as requested by Herbert Xu.
- verify op signature de-kmemdup'ed (as requested by David Howells) in separate
patch (as requested by Herbert Xu).
- Add forgotten ASN.1 parser files to EC-RDSA patch.
- Tested on x86_64.

Changes since v5:
- Comparison of hash algo by enum id instead of text name, as suggested by
Thiago Jung Bauermann and Mimi Zohar.

Changes since RFC (v1-v4):
- akcipher set_max_size, encrypt, decrypt, sign, verify callbacks may be
undefined by the drivers, so their crypto_akcipher_* frontends check for
their presence before passing the call.
- supported_ops flags are set for keyctl, based on the presence of implemented
akcipher callbacks.
- Transition to verify2 API is abandoned because raw RSA does not need
sign/verify ops at all, and we can switch to the new verify in one step.
For this RSA backends have sign/verify ops removed as they should only
be used (and actually used only) via PKCS1 driver.
- Verify callback requires digest as the input parameter in src SGL, as
suggested by Herbert Xu, (instead of a separate parameter, as it was in
verify2).
- For verify op signature is moved into kmalloc'd memory as suggested by
Herbert Xu.
- set_params API should be called before set_{pub,priv}_key, thus set_*_key
knows everything it needs to set they key properly. Also, set_params made
optional for back compatibility with RSA drivers.
- Public-key cryptography section is created in Kconfig.
- ecc.c is made into separate module object, to be used together by ECDH and
EC-RDSA.
- EC-RDSA parameters and public key are parsed using asn1_ber_decoder as
suggested by Stephan Mueller and David Howells.
- Test vectors are added and tests are passing.
- Curves/parameters definitions are split from ecrdsa.c into ecrdsa_defs.h.
- Integration with IMA in asymmetric_verify(). Userspace ima-evm-utils already
have a patch in the queue to support this. Tested on x86_64.

Vitaly Chikunov (11):
KEYS: report to keyctl only actually supported key ops
crypto: akcipher - check the presence of callback before the call
crypto: rsa - unimplement sign/verify for raw RSA backends
crypto: akcipher - new verify API for public key algorithms
KEYS: do not kmemdup digest in {public,tpm}_key_verify_signature
X.509: parse public key parameters from x509 for akcipher
crypto: Kconfig - create Public-key cryptography section
crypto: ecc - make ecc into separate module
crypto: ecrdsa - add EC-RDSA (GOST 34.10) algorithm
crypto: ecrdsa - add EC-RDSA test vectors to testmgr
integrity: support EC-RDSA signatures for asymmetric_verify

crypto/Kconfig | 63 ++--
crypto/Makefile | 10 +-
crypto/asymmetric_keys/asym_tpm.c | 77 +++--
crypto/asymmetric_keys/public_key.c | 121 +++++---
crypto/asymmetric_keys/x509.asn1 | 2 +-
crypto/asymmetric_keys/x509_cert_parser.c | 57 +++-
crypto/ecc.c | 417 +++++++++++++++++++++++++-
crypto/ecc.h | 153 +++++++++-
crypto/ecc_curve_defs.h | 15 -
crypto/ecrdsa.c | 299 ++++++++++++++++++
crypto/ecrdsa_defs.h | 225 ++++++++++++++
crypto/rsa-pkcs1pad.c | 33 +-
crypto/rsa.c | 109 -------
crypto/testmgr.c | 80 +++--
crypto/testmgr.h | 159 ++++++++++
drivers/crypto/caam/caampkc.c | 2 -
drivers/crypto/ccp/ccp-crypto-rsa.c | 2 -
drivers/crypto/qat/qat_common/qat_asym_algs.c | 2 -
include/crypto/akcipher.h | 81 +++--
include/crypto/public_key.h | 4 +
include/linux/oid_registry.h | 18 ++
security/integrity/digsig_asymmetric.c | 11 +-
22 files changed, 1619 insertions(+), 321 deletions(-)
create mode 100644 crypto/ecrdsa.c
create mode 100644 crypto/ecrdsa_defs.h

--
2.11.0



2019-03-01 17:59:29

by Vitaly Chikunov

[permalink] [raw]
Subject: [PATCH v7 01/11] KEYS: report to keyctl only actually supported key ops

Because with the introduction of EC-RDSA and change in workings of RSA
in regard to sign/verify, akcipher may have not all callbacks defined,
report to keyctl only actually supported ops determined by the presence
of the akcipher callbacks.

Cc: David Howells <[email protected]>
Cc: [email protected]
Signed-off-by: Vitaly Chikunov <[email protected]>
---
crypto/asymmetric_keys/public_key.c | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index f5d85b47fcc6..c2e4e73fcf06 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -130,11 +130,17 @@ static int software_key_query(const struct kernel_pkey_params *params,
info->max_sig_size = len;
info->max_enc_size = len;
info->max_dec_size = len;
- info->supported_ops = (KEYCTL_SUPPORTS_ENCRYPT |
- KEYCTL_SUPPORTS_VERIFY);
- if (pkey->key_is_private)
- info->supported_ops |= (KEYCTL_SUPPORTS_DECRYPT |
- KEYCTL_SUPPORTS_SIGN);
+ info->supported_ops = 0;
+ if (crypto_akcipher_alg(tfm)->verify)
+ info->supported_ops |= KEYCTL_SUPPORTS_VERIFY;
+ if (crypto_akcipher_alg(tfm)->encrypt)
+ info->supported_ops |= KEYCTL_SUPPORTS_ENCRYPT;
+ if (pkey->key_is_private) {
+ if (crypto_akcipher_alg(tfm)->decrypt)
+ info->supported_ops |= KEYCTL_SUPPORTS_DECRYPT;
+ if (crypto_akcipher_alg(tfm)->sign)
+ info->supported_ops |= KEYCTL_SUPPORTS_SIGN;
+ }
ret = 0;

error_free_tfm:
--
2.11.0


2019-03-01 17:59:34

by Vitaly Chikunov

[permalink] [raw]
Subject: [PATCH v7 04/11] crypto: akcipher - new verify API for public key algorithms

Previous akcipher .verify() just `decrypts' (using RSA encrypt which is
using public key) signature to uncover message hash, which was then
compared in upper level public_key_verify_signature() with the expected
hash value, which itself was never passed into verify().

This approach was incompatible with EC-DSA family of algorithms,
because, to verify a signature EC-DSA algorithm also needs a hash value
as input; then it's used (together with a signature divided into halves
`r||s') to produce a witness value, which is then compared with `r' to
determine if the signature is correct. Thus, for EC-DSA, nor
requirements of .verify() itself, nor its output expectations in
public_key_verify_signature() wasn't sufficient.

Make improved .verify() call which gets hash value as input and produce
complete signature check without any output besides status.

Now for the top level verification only crypto_akcipher_verify() needs
to be called.

Make sure that `digest' is in kmalloc'd memory (in place of `output`) in
{public,tpm}_key_verify_signature() as insisted by Herbert Xu, and will
be changed in the following commit.

Cc: David Howells <[email protected]>
Cc: [email protected]
Signed-off-by: Vitaly Chikunov <[email protected]>
---
crypto/asymmetric_keys/asym_tpm.c | 34 ++++++++-----------------
crypto/asymmetric_keys/public_key.c | 34 ++++++++-----------------
crypto/rsa-pkcs1pad.c | 29 +++++++++++++--------
crypto/testmgr.c | 50 ++++++++++++++++++++++---------------
include/crypto/akcipher.h | 40 ++++++++++++++++++-----------
5 files changed, 95 insertions(+), 92 deletions(-)

diff --git a/crypto/asymmetric_keys/asym_tpm.c b/crypto/asymmetric_keys/asym_tpm.c
index 5d4c270463f6..4e5b6fb57a94 100644
--- a/crypto/asymmetric_keys/asym_tpm.c
+++ b/crypto/asymmetric_keys/asym_tpm.c
@@ -744,12 +744,11 @@ static int tpm_key_verify_signature(const struct key *key,
struct crypto_wait cwait;
struct crypto_akcipher *tfm;
struct akcipher_request *req;
- struct scatterlist sig_sg, digest_sg;
+ struct scatterlist src_sg[2];
char alg_name[CRYPTO_MAX_ALG_NAME];
uint8_t der_pub_key[PUB_KEY_BUF_SIZE];
uint32_t der_pub_key_len;
- void *output;
- unsigned int outlen;
+ void *digest;
int ret;

pr_devel("==>%s()\n", __func__);
@@ -782,35 +781,22 @@ static int tpm_key_verify_signature(const struct key *key,
goto error_free_tfm;

ret = -ENOMEM;
- outlen = crypto_akcipher_maxsize(tfm);
- output = kmalloc(outlen, GFP_KERNEL);
- if (!output)
+ digest = kmemdup(sig->digest, sig->digest_size, GFP_KERNEL);
+ if (!digest)
goto error_free_req;

- sg_init_one(&sig_sg, sig->s, sig->s_size);
- sg_init_one(&digest_sg, output, outlen);
- akcipher_request_set_crypt(req, &sig_sg, &digest_sg, sig->s_size,
- outlen);
+ sg_init_table(src_sg, 2);
+ sg_set_buf(&src_sg[0], sig->s, sig->s_size);
+ sg_set_buf(&src_sg[1], digest, sig->digest_size);
+ akcipher_request_set_crypt(req, src_sg, NULL, sig->s_size,
+ sig->digest_size);
crypto_init_wait(&cwait);
akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
CRYPTO_TFM_REQ_MAY_SLEEP,
crypto_req_done, &cwait);
-
- /* Perform the verification calculation. This doesn't actually do the
- * verification, but rather calculates the hash expected by the
- * signature and returns that to us.
- */
ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait);
- if (ret)
- goto out_free_output;
-
- /* Do the actual verification step. */
- if (req->dst_len != sig->digest_size ||
- memcmp(sig->digest, output, sig->digest_size) != 0)
- ret = -EKEYREJECTED;

-out_free_output:
- kfree(output);
+ kfree(digest);
error_free_req:
akcipher_request_free(req);
error_free_tfm:
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index c2e4e73fcf06..338f2b5352b1 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -233,10 +233,9 @@ int public_key_verify_signature(const struct public_key *pkey,
struct crypto_wait cwait;
struct crypto_akcipher *tfm;
struct akcipher_request *req;
- struct scatterlist sig_sg, digest_sg;
+ struct scatterlist src_sg[2];
char alg_name[CRYPTO_MAX_ALG_NAME];
- void *output;
- unsigned int outlen;
+ void *digest;
int ret;

pr_devel("==>%s()\n", __func__);
@@ -270,35 +269,22 @@ int public_key_verify_signature(const struct public_key *pkey,
goto error_free_req;

ret = -ENOMEM;
- outlen = crypto_akcipher_maxsize(tfm);
- output = kmalloc(outlen, GFP_KERNEL);
- if (!output)
+ digest = kmemdup(sig->digest, sig->digest_size, GFP_KERNEL);
+ if (!digest)
goto error_free_req;

- sg_init_one(&sig_sg, sig->s, sig->s_size);
- sg_init_one(&digest_sg, output, outlen);
- akcipher_request_set_crypt(req, &sig_sg, &digest_sg, sig->s_size,
- outlen);
+ sg_init_table(src_sg, 2);
+ sg_set_buf(&src_sg[0], sig->s, sig->s_size);
+ sg_set_buf(&src_sg[1], digest, sig->digest_size);
+ akcipher_request_set_crypt(req, src_sg, NULL, sig->s_size,
+ sig->digest_size);
crypto_init_wait(&cwait);
akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
CRYPTO_TFM_REQ_MAY_SLEEP,
crypto_req_done, &cwait);
-
- /* Perform the verification calculation. This doesn't actually do the
- * verification, but rather calculates the hash expected by the
- * signature and returns that to us.
- */
ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait);
- if (ret)
- goto out_free_output;
-
- /* Do the actual verification step. */
- if (req->dst_len != sig->digest_size ||
- memcmp(sig->digest, output, sig->digest_size) != 0)
- ret = -EKEYREJECTED;

-out_free_output:
- kfree(output);
+ kfree(digest);
error_free_req:
akcipher_request_free(req);
error_free_tfm:
diff --git a/crypto/rsa-pkcs1pad.c b/crypto/rsa-pkcs1pad.c
index 94382fa2c6ac..29c336068dc0 100644
--- a/crypto/rsa-pkcs1pad.c
+++ b/crypto/rsa-pkcs1pad.c
@@ -488,14 +488,21 @@ static int pkcs1pad_verify_complete(struct akcipher_request *req, int err)

err = 0;

- if (req->dst_len < dst_len - pos)
- err = -EOVERFLOW;
- req->dst_len = dst_len - pos;
-
- if (!err)
- sg_copy_from_buffer(req->dst,
- sg_nents_for_len(req->dst, req->dst_len),
- out_buf + pos, req->dst_len);
+ if (req->dst_len != dst_len - pos) {
+ err = -EKEYREJECTED;
+ req->dst_len = dst_len - pos;
+ goto done;
+ }
+ /* Extract appended digest. */
+ sg_pcopy_to_buffer(req->src,
+ sg_nents_for_len(req->src,
+ req->src_len + req->dst_len),
+ req_ctx->out_buf + ctx->key_size,
+ req->dst_len, ctx->key_size);
+ /* Do the actual verification step. */
+ if (memcmp(req_ctx->out_buf + ctx->key_size, out_buf + pos,
+ req->dst_len) != 0)
+ err = -EKEYREJECTED;
done:
kzfree(req_ctx->out_buf);

@@ -532,10 +539,12 @@ static int pkcs1pad_verify(struct akcipher_request *req)
struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req);
int err;

- if (!ctx->key_size || req->src_len < ctx->key_size)
+ if (WARN_ON(req->dst) ||
+ WARN_ON(!req->dst_len) ||
+ !ctx->key_size || req->src_len < ctx->key_size)
return -EINVAL;

- req_ctx->out_buf = kmalloc(ctx->key_size, GFP_KERNEL);
+ req_ctx->out_buf = kmalloc(ctx->key_size + req->dst_len, GFP_KERNEL);
if (!req_ctx->out_buf)
return -ENOMEM;

diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 8386038d67c7..443d5b6f1045 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -2503,7 +2503,7 @@ static int test_akcipher_one(struct crypto_akcipher *tfm,
struct crypto_wait wait;
unsigned int out_len_max, out_len = 0;
int err = -ENOMEM;
- struct scatterlist src, dst, src_tab[2];
+ struct scatterlist src, dst, src_tab[3];
const char *m, *c;
unsigned int m_size, c_size;
const char *op;
@@ -2526,13 +2526,12 @@ static int test_akcipher_one(struct crypto_akcipher *tfm,
if (err)
goto free_req;

- err = -ENOMEM;
- out_len_max = crypto_akcipher_maxsize(tfm);
-
/*
* First run test which do not require a private key, such as
* encrypt or verify.
*/
+ err = -ENOMEM;
+ out_len_max = crypto_akcipher_maxsize(tfm);
outbuf_enc = kzalloc(out_len_max, GFP_KERNEL);
if (!outbuf_enc)
goto free_req;
@@ -2558,12 +2557,20 @@ static int test_akcipher_one(struct crypto_akcipher *tfm,
goto free_all;
memcpy(xbuf[0], m, m_size);

- sg_init_table(src_tab, 2);
+ sg_init_table(src_tab, 3);
sg_set_buf(&src_tab[0], xbuf[0], 8);
sg_set_buf(&src_tab[1], xbuf[0] + 8, m_size - 8);
- sg_init_one(&dst, outbuf_enc, out_len_max);
- akcipher_request_set_crypt(req, src_tab, &dst, m_size,
- out_len_max);
+ if (vecs->siggen_sigver_test) {
+ if (WARN_ON(c_size > PAGE_SIZE))
+ goto free_all;
+ memcpy(xbuf[1], c, c_size);
+ sg_set_buf(&src_tab[2], xbuf[1], c_size);
+ akcipher_request_set_crypt(req, src_tab, NULL, m_size, c_size);
+ } else {
+ sg_init_one(&dst, outbuf_enc, out_len_max);
+ akcipher_request_set_crypt(req, src_tab, &dst, m_size,
+ out_len_max);
+ }
akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
crypto_req_done, &wait);

@@ -2576,18 +2583,21 @@ static int test_akcipher_one(struct crypto_akcipher *tfm,
pr_err("alg: akcipher: %s test failed. err %d\n", op, err);
goto free_all;
}
- if (req->dst_len != c_size) {
- pr_err("alg: akcipher: %s test failed. Invalid output len\n",
- op);
- err = -EINVAL;
- goto free_all;
- }
- /* verify that encrypted message is equal to expected */
- if (memcmp(c, outbuf_enc, c_size)) {
- pr_err("alg: akcipher: %s test failed. Invalid output\n", op);
- hexdump(outbuf_enc, c_size);
- err = -EINVAL;
- goto free_all;
+ if (!vecs->siggen_sigver_test) {
+ if (req->dst_len != c_size) {
+ pr_err("alg: akcipher: %s test failed. Invalid output len\n",
+ op);
+ err = -EINVAL;
+ goto free_all;
+ }
+ /* verify that encrypted message is equal to expected */
+ if (memcmp(c, outbuf_enc, c_size) != 0) {
+ pr_err("alg: akcipher: %s test failed. Invalid output\n",
+ op);
+ hexdump(outbuf_enc, c_size);
+ err = -EINVAL;
+ goto free_all;
+ }
}

/*
diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
index f537fad1989f..28ffa9ef03a9 100644
--- a/include/crypto/akcipher.h
+++ b/include/crypto/akcipher.h
@@ -19,14 +19,20 @@
*
* @base: Common attributes for async crypto requests
* @src: Source data
- * @dst: Destination data
+ * For verify op this is signature + digest, in that case
+ * total size of @src is @src_len + @dst_len.
+ * @dst: Destination data (Should be NULL for verify op)
* @src_len: Size of the input buffer
- * @dst_len: Size of the output buffer. It needs to be at least
- * as big as the expected result depending on the operation
+ * For verify op it's size of signature part of @src, this part
+ * is supposed to be operated by cipher.
+ * @dst_len: Size of @dst buffer (for all ops except verify).
+ * It needs to be at least as big as the expected result
+ * depending on the operation.
* After operation it will be updated with the actual size of the
* result.
* In case of error where the dst sgl size was insufficient,
* it will be updated to the size required for the operation.
+ * For verify op this is size of digest part in @src.
* @__ctx: Start of private context data
*/
struct akcipher_request {
@@ -55,10 +61,9 @@ struct crypto_akcipher {
* algorithm. In case of error, where the dst_len was insufficient,
* the req->dst_len will be updated to the size required for the
* operation
- * @verify: Function performs a sign operation as defined by public key
- * algorithm. In case of error, where the dst_len was insufficient,
- * the req->dst_len will be updated to the size required for the
- * operation
+ * @verify: Function performs a complete verify operation as defined by
+ * public key algorithm, returning verification status. Requires
+ * digest value as input parameter.
* @encrypt: Function performs an encrypt operation as defined by public key
* algorithm. In case of error, where the dst_len was insufficient,
* the req->dst_len will be updated to the size required for the
@@ -238,9 +243,10 @@ static inline void akcipher_request_set_callback(struct akcipher_request *req,
*
* @req: public key request
* @src: ptr to input scatter list
- * @dst: ptr to output scatter list
+ * @dst: ptr to output scatter list or NULL for verify op
* @src_len: size of the src input scatter list to be processed
- * @dst_len: size of the dst output scatter list
+ * @dst_len: size of the dst output scatter list or size of signature
+ * portion in @src for verify op
*/
static inline void akcipher_request_set_crypt(struct akcipher_request *req,
struct scatterlist *src,
@@ -349,14 +355,18 @@ static inline int crypto_akcipher_sign(struct akcipher_request *req)
}

/**
- * crypto_akcipher_verify() - Invoke public key verify operation
+ * crypto_akcipher_verify() - Invoke public key signature verification
*
- * Function invokes the specific public key verify operation for a given
- * public key algorithm
+ * Function invokes the specific public key signature verification operation
+ * for a given public key algorithm.
*
* @req: asymmetric key request
*
- * Return: zero on success; error code in case of error
+ * Note: req->dst should be NULL, req->src should point to SG of size
+ * (req->src_size + req->dst_size), containing signature (of req->src_size
+ * length) with appended digest (of req->dst_size length).
+ *
+ * Return: zero on verification success; error code in case of error.
*/
static inline int crypto_akcipher_verify(struct akcipher_request *req)
{
@@ -366,7 +376,9 @@ static inline int crypto_akcipher_verify(struct akcipher_request *req)
int ret = -ENOSYS;

crypto_stats_get(calg);
- if (alg->verify)
+ if (req->dst || !req->dst_len)
+ ret = -EINVAL;
+ else if (alg->verify)
ret = alg->verify(req);
crypto_stats_akcipher_verify(ret, calg);
return ret;
--
2.11.0


2019-03-01 17:59:50

by Vitaly Chikunov

[permalink] [raw]
Subject: [PATCH v7 09/11] crypto: ecrdsa - add EC-RDSA (GOST 34.10) algorithm

Add Elliptic Curve Russian Digital Signature Algorithm (GOST R
34.10-2012, RFC 7091, ISO/IEC 14888-3) is one of the Russian (and since
2018 the CIS countries) cryptographic standard algorithms (called GOST
algorithms). Only signature verification is supported, with intent to be
used in the IMA.

Summary of the changes:

* crypto/Kconfig:
- EC-RDSA is added into Public-key cryptography section.

* crypto/Makefile:
- ecrdsa objects are added.

* crypto/asymmetric_keys/x509_cert_parser.c:
- Recognize EC-RDSA and Streebog OIDs.

* include/linux/oid_registry.h:
- EC-RDSA OIDs are added to the enum. Also, a two currently not
implemented curve OIDs are added for possible extension later (to
not change numbering and grouping).

* crypto/ecc.c:
- Kenneth MacKay copyright date is updated to 2014, because
vli_mmod_slow, ecc_point_add, ecc_point_mult_shamir are based on his
code from micro-ecc.
- Functions needed for ecrdsa are EXPORT_SYMBOL'ed.
- New functions:
vli_is_negative - helper to determine sign of vli;
vli_from_be64 - unpack big-endian array into vli (used for
a signature);
vli_from_le64 - unpack little-endian array into vli (used for
a public key);
vli_uadd, vli_usub - add/sub u64 value to/from vli (used for
increment/decrement);
mul_64_64 - optimized to use __int128 where appropriate, this speeds
up point multiplication (and as a consequence signature
verification) by the factor of 1.5-2;
vli_umult - multiply vli by a small value (speeds up point
multiplication by another factor of 1.5-2, depending on vli sizes);
vli_mmod_special - module reduction for some form of Pseudo-Mersenne
primes (used for the curves A);
vli_mmod_special2 - module reduction for another form of
Pseudo-Mersenne primes (used for the curves B);
vli_mmod_barrett - module reduction using pre-computed value (used
for the curve C);
vli_mmod_slow - more general module reduction which is much slower
(used when the modulus is subgroup order);
vli_mod_mult_slow - modular multiplication;
ecc_point_add - add two points;
ecc_point_mult_shamir - add two points multiplied by scalars in one
combined multiplication (this gives speed up by another factor 2 in
compare to two separate multiplications).
ecc_is_pubkey_valid_partial - additional samity check is added.
- Updated vli_mmod_fast with non-strict heuristic to call optimal
module reduction function depending on the prime value;
- All computations for the previously defined (two NIST) curves should
not unaffected.

* crypto/ecc.h:
- Newly exported functions are documented.

* crypto/ecrdsa_defs.h
- Five curves are defined.

* crypto/ecrdsa.c:
- Signature verification is implemented.

* crypto/ecrdsa_params.asn1, crypto/ecrdsa_pub_key.asn1:
- Templates for BER decoder for EC-RDSA parameters and public key.

Cc: [email protected]
Signed-off-by: Vitaly Chikunov <[email protected]>
---
crypto/Kconfig | 11 +
crypto/Makefile | 8 +
crypto/asymmetric_keys/x509_cert_parser.c | 26 +-
crypto/ecc.c | 392 +++++++++++++++++++++++++++++-
crypto/ecc.h | 54 +++-
crypto/ecrdsa.c | 299 +++++++++++++++++++++++
crypto/ecrdsa_defs.h | 225 +++++++++++++++++
crypto/ecrdsa_params.asn1 | 4 +
crypto/ecrdsa_pub_key.asn1 | 1 +
include/linux/oid_registry.h | 18 ++
10 files changed, 1025 insertions(+), 13 deletions(-)
create mode 100644 crypto/ecrdsa.c
create mode 100644 crypto/ecrdsa_defs.h
create mode 100644 crypto/ecrdsa_params.asn1
create mode 100644 crypto/ecrdsa_pub_key.asn1

diff --git a/crypto/Kconfig b/crypto/Kconfig
index cf0bceee0ea5..c7e7e3ac38ed 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -259,6 +259,17 @@ config CRYPTO_ECDH
help
Generic implementation of the ECDH algorithm

+config CRYPTO_ECRDSA
+ tristate "EC-RDSA (GOST 34.10) algorithm"
+ select CRYPTO_ECC
+ select CRYPTO_AKCIPHER
+ select CRYPTO_STREEBOG
+ help
+ Elliptic Curve Russian Digital Signature Algorithm (GOST R 34.10-2012,
+ RFC 7091, ISO/IEC 14888-3:2018) is one of the Russian cryptographic
+ standard algorithms (called GOST algorithms). Only signature verification
+ is supported.
+
comment "Authenticated Encryption with Associated Data"

config CRYPTO_CCM
diff --git a/crypto/Makefile b/crypto/Makefile
index b660f078651a..89e5e55bf391 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -153,6 +153,14 @@ ecdh_generic-y += ecdh.o
ecdh_generic-y += ecdh_helper.o
obj-$(CONFIG_CRYPTO_ECDH) += ecdh_generic.o

+$(obj)/ecrdsa_params.asn1.o: $(obj)/ecrdsa_params.asn1.c $(obj)/ecrdsa_params.asn1.h
+$(obj)/ecrdsa_pub_key.asn1.o: $(obj)/ecrdsa_pub_key.asn1.c $(obj)/ecrdsa_pub_key.asn1.h
+$(obj)/ecrdsa.o: $(obj)/ecrdsa_params.asn1.h $(obj)/ecrdsa_pub_key.asn1.h
+ecrdsa_generic-y += ecrdsa.o
+ecrdsa_generic-y += ecrdsa_params.asn1.o
+ecrdsa_generic-y += ecrdsa_pub_key.asn1.o
+obj-$(CONFIG_CRYPTO_ECRDSA) += ecrdsa_generic.o
+
#
# generic algorithms and the async_tx api
#
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
index b2cdf2db1987..5b7bfd95c334 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -230,6 +230,14 @@ int x509_note_pkey_algo(void *context, size_t hdrlen,
case OID_sha224WithRSAEncryption:
ctx->cert->sig->hash_algo = "sha224";
goto rsa_pkcs1;
+
+ case OID_gost2012Signature256:
+ ctx->cert->sig->hash_algo = "streebog256";
+ goto ecrdsa;
+
+ case OID_gost2012Signature512:
+ ctx->cert->sig->hash_algo = "streebog512";
+ goto ecrdsa;
}

rsa_pkcs1:
@@ -237,6 +245,11 @@ int x509_note_pkey_algo(void *context, size_t hdrlen,
ctx->cert->sig->encoding = "pkcs1";
ctx->algo_oid = ctx->last_oid;
return 0;
+ecrdsa:
+ ctx->cert->sig->pkey_algo = "ecrdsa";
+ ctx->cert->sig->encoding = "raw";
+ ctx->algo_oid = ctx->last_oid;
+ return 0;
}

/*
@@ -256,7 +269,8 @@ int x509_note_signature(void *context, size_t hdrlen,
return -EINVAL;
}

- if (strcmp(ctx->cert->sig->pkey_algo, "rsa") == 0) {
+ if (strcmp(ctx->cert->sig->pkey_algo, "rsa") == 0 ||
+ strcmp(ctx->cert->sig->pkey_algo, "ecrdsa") == 0) {
/* Discard the BIT STRING metadata */
if (vlen < 1 || *(const u8 *)value != 0)
return -EBADMSG;
@@ -440,11 +454,15 @@ int x509_extract_key_data(void *context, size_t hdrlen,
{
struct x509_parse_context *ctx = context;

- if (ctx->last_oid != OID_rsaEncryption)
+ ctx->key_algo = ctx->last_oid;
+ if (ctx->last_oid == OID_rsaEncryption)
+ ctx->cert->pub->pkey_algo = "rsa";
+ else if (ctx->last_oid == OID_gost2012PKey256 ||
+ ctx->last_oid == OID_gost2012PKey512)
+ ctx->cert->pub->pkey_algo = "ecrdsa";
+ else
return -ENOPKG;

- ctx->cert->pub->pkey_algo = "rsa";
-
/* Discard the BIT STRING metadata */
if (vlen < 1 || *(const u8 *)value != 0)
return -EBADMSG;
diff --git a/crypto/ecc.c b/crypto/ecc.c
index 5f36792d143d..dfe114bc0c4a 100644
--- a/crypto/ecc.c
+++ b/crypto/ecc.c
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2013, Kenneth MacKay
- * All rights reserved.
+ * Copyright (c) 2013, 2014 Kenneth MacKay. All rights reserved.
+ * Copyright (c) 2019 Vitaly Chikunov <[email protected]>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -31,6 +31,8 @@
#include <linux/fips.h>
#include <crypto/ecdh.h>
#include <crypto/rng.h>
+#include <asm/unaligned.h>
+#include <linux/ratelimit.h>

#include "ecc.h"
#include "ecc_curve_defs.h"
@@ -132,6 +134,11 @@ static u64 vli_test_bit(const u64 *vli, unsigned int bit)
return (vli[bit / 64] & ((u64)1 << (bit % 64)));
}

+static bool vli_is_negative(const u64 *vli, unsigned int ndigits)
+{
+ return vli_test_bit(vli, ndigits * 64 - 1);
+}
+
/* Counts the number of 64-bit "digits" in vli. */
static unsigned int vli_num_digits(const u64 *vli, unsigned int ndigits)
{
@@ -163,6 +170,27 @@ static unsigned int vli_num_bits(const u64 *vli, unsigned int ndigits)
return ((num_digits - 1) * 64 + i);
}

+/* Set dest from unaligned bit string src. */
+void vli_from_be64(u64 *dest, const void *src, unsigned int ndigits)
+{
+ int i;
+ const u64 *from = src;
+
+ for (i = 0; i < ndigits; i++)
+ dest[i] = get_unaligned_be64(&from[ndigits - 1 - i]);
+}
+EXPORT_SYMBOL(vli_from_be64);
+
+void vli_from_le64(u64 *dest, const void *src, unsigned int ndigits)
+{
+ int i;
+ const u64 *from = src;
+
+ for (i = 0; i < ndigits; i++)
+ dest[i] = get_unaligned_le64(&from[i]);
+}
+EXPORT_SYMBOL(vli_from_le64);
+
/* Sets dest = src. */
static void vli_set(u64 *dest, const u64 *src, unsigned int ndigits)
{
@@ -242,6 +270,28 @@ static u64 vli_add(u64 *result, const u64 *left, const u64 *right,
return carry;
}

+/* Computes result = left + right, returning carry. Can modify in place. */
+static u64 vli_uadd(u64 *result, const u64 *left, u64 right,
+ unsigned int ndigits)
+{
+ u64 carry = right;
+ int i;
+
+ for (i = 0; i < ndigits; i++) {
+ u64 sum;
+
+ sum = left[i] + carry;
+ if (sum != left[i])
+ carry = (sum < left[i]);
+ else
+ carry = !!carry;
+
+ result[i] = sum;
+ }
+
+ return carry;
+}
+
/* Computes result = left - right, returning borrow. Can modify in place. */
u64 vli_sub(u64 *result, const u64 *left, const u64 *right,
unsigned int ndigits)
@@ -263,8 +313,35 @@ u64 vli_sub(u64 *result, const u64 *left, const u64 *right,
}
EXPORT_SYMBOL(vli_sub);

+/* Computes result = left - right, returning borrow. Can modify in place. */
+static u64 vli_usub(u64 *result, const u64 *left, u64 right,
+ unsigned int ndigits)
+{
+ u64 borrow = right;
+ int i;
+
+ for (i = 0; i < ndigits; i++) {
+ u64 diff;
+
+ diff = left[i] - borrow;
+ if (diff != left[i])
+ borrow = (diff > left[i]);
+
+ result[i] = diff;
+ }
+
+ return borrow;
+}
+
static uint128_t mul_64_64(u64 left, u64 right)
{
+ uint128_t result;
+#if defined(CONFIG_ARCH_SUPPORTS_INT128) && defined(__SIZEOF_INT128__)
+ unsigned __int128 m = (unsigned __int128)left * right;
+
+ result.m_low = m;
+ result.m_high = m >> 64;
+#else
u64 a0 = left & 0xffffffffull;
u64 a1 = left >> 32;
u64 b0 = right & 0xffffffffull;
@@ -273,7 +350,6 @@ static uint128_t mul_64_64(u64 left, u64 right)
u64 m1 = a0 * b1;
u64 m2 = a1 * b0;
u64 m3 = a1 * b1;
- uint128_t result;

m2 += (m0 >> 32);
m2 += m1;
@@ -284,7 +360,7 @@ static uint128_t mul_64_64(u64 left, u64 right)

result.m_low = (m0 & 0xffffffffull) | (m2 << 32);
result.m_high = m3 + (m2 >> 32);
-
+#endif
return result;
}

@@ -334,6 +410,28 @@ static void vli_mult(u64 *result, const u64 *left, const u64 *right,
result[ndigits * 2 - 1] = r01.m_low;
}

+/* Compute product = left * right, for a small right value. */
+static void vli_umult(u64 *result, const u64 *left, u32 right,
+ unsigned int ndigits)
+{
+ uint128_t r01 = { 0 };
+ unsigned int k;
+
+ for (k = 0; k < ndigits; k++) {
+ uint128_t product;
+
+ product = mul_64_64(left[k], right);
+ r01 = add_128_128(r01, product);
+ /* no carry */
+ result[k] = r01.m_low;
+ r01.m_low = r01.m_high;
+ r01.m_high = 0;
+ }
+ result[k] = r01.m_low;
+ for (++k; k < ndigits * 2; k++)
+ result[k] = 0;
+}
+
static void vli_square(u64 *result, const u64 *left, unsigned int ndigits)
{
uint128_t r01 = { 0, 0 };
@@ -406,6 +504,170 @@ static void vli_mod_sub(u64 *result, const u64 *left, const u64 *right,
vli_add(result, result, mod, ndigits);
}

+/*
+ * Computes result = product % mod
+ * for special form moduli: p = 2^k-c, for small c (note the minus sign)
+ *
+ * References:
+ * R. Crandall, C. Pomerance. Prime Numbers: A Computational Perspective.
+ * 9 Fast Algorithms for Large-Integer Arithmetic. 9.2.3 Moduli of special form
+ * Algorithm 9.2.13 (Fast mod operation for special-form moduli).
+ */
+static void vli_mmod_special(u64 *result, const u64 *product,
+ const u64 *mod, unsigned int ndigits)
+{
+ u64 c = -mod[0];
+ u64 t[ECC_MAX_DIGITS * 2];
+ u64 r[ECC_MAX_DIGITS * 2];
+
+ vli_set(r, product, ndigits * 2);
+ while (!vli_is_zero(r + ndigits, ndigits)) {
+ vli_umult(t, r + ndigits, c, ndigits);
+ vli_clear(r + ndigits, ndigits);
+ vli_add(r, r, t, ndigits * 2);
+ }
+ vli_set(t, mod, ndigits);
+ vli_clear(t + ndigits, ndigits);
+ while (vli_cmp(r, t, ndigits * 2) >= 0)
+ vli_sub(r, r, t, ndigits * 2);
+ vli_set(result, r, ndigits);
+}
+
+/*
+ * Computes result = product % mod
+ * for special form moduli: p = 2^{k-1}+c, for small c (note the plus sign)
+ * where k-1 does not fit into qword boundary by -1 bit (such as 255).
+
+ * References (loosely based on):
+ * A. Menezes, P. van Oorschot, S. Vanstone. Handbook of Applied Cryptography.
+ * 14.3.4 Reduction methods for moduli of special form. Algorithm 14.47.
+ * URL: http://cacr.uwaterloo.ca/hac/about/chap14.pdf
+ *
+ * H. Cohen, G. Frey, R. Avanzi, C. Doche, T. Lange, K. Nguyen, F. Vercauteren.
+ * Handbook of Elliptic and Hyperelliptic Curve Cryptography.
+ * Algorithm 10.25 Fast reduction for special form moduli
+ */
+static void vli_mmod_special2(u64 *result, const u64 *product,
+ const u64 *mod, unsigned int ndigits)
+{
+ u64 c2 = mod[0] * 2;
+ u64 q[ECC_MAX_DIGITS];
+ u64 r[ECC_MAX_DIGITS * 2];
+ u64 m[ECC_MAX_DIGITS * 2]; /* expanded mod */
+ int carry; /* last bit that doesn't fit into q */
+ int i;
+
+ vli_set(m, mod, ndigits);
+ vli_clear(m + ndigits, ndigits);
+
+ vli_set(r, product, ndigits);
+ /* q and carry are top bits */
+ vli_set(q, product + ndigits, ndigits);
+ vli_clear(r + ndigits, ndigits);
+ carry = vli_is_negative(r, ndigits);
+ if (carry)
+ r[ndigits - 1] &= (1ull << 63) - 1;
+ for (i = 1; carry || !vli_is_zero(q, ndigits); i++) {
+ u64 qc[ECC_MAX_DIGITS * 2];
+
+ vli_umult(qc, q, c2, ndigits);
+ if (carry)
+ vli_uadd(qc, qc, mod[0], ndigits * 2);
+ vli_set(q, qc + ndigits, ndigits);
+ vli_clear(qc + ndigits, ndigits);
+ carry = vli_is_negative(qc, ndigits);
+ if (carry)
+ qc[ndigits - 1] &= (1ull << 63) - 1;
+ if (i & 1)
+ vli_sub(r, r, qc, ndigits * 2);
+ else
+ vli_add(r, r, qc, ndigits * 2);
+ }
+ while (vli_is_negative(r, ndigits * 2))
+ vli_add(r, r, m, ndigits * 2);
+ while (vli_cmp(r, m, ndigits * 2) >= 0)
+ vli_sub(r, r, m, ndigits * 2);
+
+ vli_set(result, r, ndigits);
+}
+
+/*
+ * Computes result = product % mod, where product is 2N words long.
+ * Reference: Ken MacKay's micro-ecc.
+ * Currently only designed to work for curve_p or curve_n.
+ */
+static void vli_mmod_slow(u64 *result, u64 *product, const u64 *mod,
+ unsigned int ndigits)
+{
+ u64 mod_m[2 * ECC_MAX_DIGITS];
+ u64 tmp[2 * ECC_MAX_DIGITS];
+ u64 *v[2] = { tmp, product };
+ u64 carry = 0;
+ unsigned int i;
+ /* Shift mod so its highest set bit is at the maximum position. */
+ int shift = (ndigits * 2 * 64) - vli_num_bits(mod, ndigits);
+ int word_shift = shift / 64;
+ int bit_shift = shift % 64;
+
+ vli_clear(mod_m, word_shift);
+ if (bit_shift > 0) {
+ for (i = 0; i < ndigits; ++i) {
+ mod_m[word_shift + i] = (mod[i] << bit_shift) | carry;
+ carry = mod[i] >> (64 - bit_shift);
+ }
+ } else
+ vli_set(mod_m + word_shift, mod, ndigits);
+
+ for (i = 1; shift >= 0; --shift) {
+ u64 borrow = 0;
+ unsigned int j;
+
+ for (j = 0; j < ndigits * 2; ++j) {
+ u64 diff = v[i][j] - mod_m[j] - borrow;
+
+ if (diff != v[i][j])
+ borrow = (diff > v[i][j]);
+ v[1 - i][j] = diff;
+ }
+ i = !(i ^ borrow); /* Swap the index if there was no borrow */
+ vli_rshift1(mod_m, ndigits);
+ mod_m[ndigits - 1] |= mod_m[ndigits] << (64 - 1);
+ vli_rshift1(mod_m + ndigits, ndigits);
+ }
+ vli_set(result, v[i], ndigits);
+}
+
+/* Computes result = product % mod using Barrett's reduction with precomputed
+ * value mu appended to the mod after ndigits, mu = (2^{2w} / mod) and have
+ * length ndigits + 1, where mu * (2^w - 1) should not overflow ndigits
+ * boundary.
+ *
+ * Reference:
+ * R. Brent, P. Zimmermann. Modern Computer Arithmetic. 2010.
+ * 2.4.1 Barrett's algorithm. Algorithm 2.5.
+ */
+static void vli_mmod_barrett(u64 *result, u64 *product, const u64 *mod,
+ unsigned int ndigits)
+{
+ u64 q[ECC_MAX_DIGITS * 2];
+ u64 r[ECC_MAX_DIGITS * 2];
+ const u64 *mu = mod + ndigits;
+
+ vli_mult(q, product + ndigits, mu, ndigits);
+ if (mu[ndigits])
+ vli_add(q + ndigits, q + ndigits, product + ndigits, ndigits);
+ vli_mult(r, mod, q + ndigits, ndigits);
+ vli_sub(r, product, r, ndigits * 2);
+ while (!vli_is_zero(r + ndigits, ndigits) ||
+ vli_cmp(r, mod, ndigits) != -1) {
+ u64 carry;
+
+ carry = vli_sub(r, r, mod, ndigits);
+ vli_usub(r + ndigits, r + ndigits, carry, ndigits);
+ }
+ vli_set(result, r, ndigits);
+}
+
/* Computes p_result = p_product % curve_p.
* See algorithm 5 and 6 from
* http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf
@@ -513,14 +775,33 @@ static void vli_mmod_fast_256(u64 *result, const u64 *product,
}
}

-/* Computes result = product % curve_prime
- * from http://www.nsa.gov/ia/_files/nist-routines.pdf
-*/
+/* Computes result = product % curve_prime for different curve_primes.
+ *
+ * Note that curve_primes are distinguished just by heuristic check and
+ * not by complete conformance check.
+ */
static bool vli_mmod_fast(u64 *result, u64 *product,
const u64 *curve_prime, unsigned int ndigits)
{
u64 tmp[2 * ECC_MAX_DIGITS];

+ /* Currently, both NIST primes have -1 in lowest qword. */
+ if (curve_prime[0] != -1ull) {
+ /* Try to handle Pseudo-Marsenne primes. */
+ if (curve_prime[ndigits - 1] == -1ull) {
+ vli_mmod_special(result, product, curve_prime,
+ ndigits);
+ return true;
+ } else if (curve_prime[ndigits - 1] == 1ull << 63 &&
+ curve_prime[ndigits - 2] == 0) {
+ vli_mmod_special2(result, product, curve_prime,
+ ndigits);
+ return true;
+ }
+ vli_mmod_barrett(result, product, curve_prime, ndigits);
+ return true;
+ }
+
switch (ndigits) {
case 3:
vli_mmod_fast_192(result, product, curve_prime, tmp);
@@ -529,13 +810,26 @@ static bool vli_mmod_fast(u64 *result, u64 *product,
vli_mmod_fast_256(result, product, curve_prime, tmp);
break;
default:
- pr_err("unsupports digits size!\n");
+ pr_err_ratelimited("ecc: unsupported digits size!\n");
return false;
}

return true;
}

+/* Computes result = (left * right) % mod.
+ * Assumes that mod is big enough curve order.
+ */
+void vli_mod_mult_slow(u64 *result, const u64 *left, const u64 *right,
+ const u64 *mod, unsigned int ndigits)
+{
+ u64 product[ECC_MAX_DIGITS * 2];
+
+ vli_mult(product, left, right, ndigits);
+ vli_mmod_slow(result, product, mod, ndigits);
+}
+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,
const u64 *curve_prime, unsigned int ndigits)
@@ -908,6 +1202,85 @@ static void ecc_point_mult(struct ecc_point *result,
vli_set(result->y, ry[0], ndigits);
}

+/* Computes R = P + Q mod p */
+static void ecc_point_add(const struct ecc_point *result,
+ const struct ecc_point *p, const struct ecc_point *q,
+ const struct ecc_curve *curve)
+{
+ u64 z[ECC_MAX_DIGITS];
+ u64 px[ECC_MAX_DIGITS];
+ u64 py[ECC_MAX_DIGITS];
+ unsigned int ndigits = curve->g.ndigits;
+
+ vli_set(result->x, q->x, ndigits);
+ vli_set(result->y, q->y, ndigits);
+ vli_mod_sub(z, result->x, p->x, curve->p, ndigits);
+ vli_set(px, p->x, ndigits);
+ vli_set(py, p->y, ndigits);
+ xycz_add(px, py, result->x, result->y, curve->p, ndigits);
+ vli_mod_inv(z, z, curve->p, ndigits);
+ apply_z(result->x, result->y, z, curve->p, ndigits);
+}
+
+/* Computes R = u1P + u2Q mod p using Shamir's trick.
+ * Based on: Kenneth MacKay's micro-ecc (2014).
+ */
+void ecc_point_mult_shamir(const struct ecc_point *result,
+ const u64 *u1, const struct ecc_point *p,
+ const u64 *u2, const struct ecc_point *q,
+ const struct ecc_curve *curve)
+{
+ u64 z[ECC_MAX_DIGITS];
+ u64 sump[2][ECC_MAX_DIGITS];
+ u64 *rx = result->x;
+ u64 *ry = result->y;
+ unsigned int ndigits = curve->g.ndigits;
+ unsigned int num_bits;
+ struct ecc_point sum = ECC_POINT_INIT(sump[0], sump[1], ndigits);
+ const struct ecc_point *points[4];
+ const struct ecc_point *point;
+ unsigned int idx;
+ int i;
+
+ ecc_point_add(&sum, p, q, curve);
+ points[0] = NULL;
+ points[1] = p;
+ points[2] = q;
+ points[3] = &sum;
+
+ num_bits = max(vli_num_bits(u1, ndigits),
+ vli_num_bits(u2, ndigits));
+ i = num_bits - 1;
+ idx = (!!vli_test_bit(u1, i)) | ((!!vli_test_bit(u2, i)) << 1);
+ point = points[idx];
+
+ vli_set(rx, point->x, ndigits);
+ vli_set(ry, point->y, ndigits);
+ vli_clear(z + 1, ndigits - 1);
+ z[0] = 1;
+
+ for (--i; i >= 0; i--) {
+ ecc_point_double_jacobian(rx, ry, z, curve->p, ndigits);
+ idx = (!!vli_test_bit(u1, i)) | ((!!vli_test_bit(u2, i)) << 1);
+ point = points[idx];
+ if (point) {
+ u64 tx[ECC_MAX_DIGITS];
+ u64 ty[ECC_MAX_DIGITS];
+ u64 tz[ECC_MAX_DIGITS];
+
+ vli_set(tx, point->x, ndigits);
+ vli_set(ty, point->y, ndigits);
+ apply_z(tx, ty, z, curve->p, ndigits);
+ vli_mod_sub(tz, rx, tx, curve->p, ndigits);
+ xycz_add(tx, ty, rx, ry, curve->p, ndigits);
+ vli_mod_mult_fast(z, z, tz, curve->p, ndigits);
+ }
+ }
+ vli_mod_inv(z, z, curve->p, ndigits);
+ apply_z(rx, ry, z, curve->p, ndigits);
+}
+EXPORT_SYMBOL(ecc_point_mult_shamir);
+
static inline void ecc_swap_digits(const u64 *in, u64 *out,
unsigned int ndigits)
{
@@ -1051,6 +1424,9 @@ int ecc_is_pubkey_valid_partial(const struct ecc_curve *curve,
{
u64 yy[ECC_MAX_DIGITS], xxx[ECC_MAX_DIGITS], w[ECC_MAX_DIGITS];

+ if (WARN_ON(pk->ndigits != curve->g.ndigits))
+ return -EINVAL;
+
/* Check 1: Verify key is not the zero point. */
if (ecc_point_is_zero(pk))
return -EINVAL;
diff --git a/crypto/ecc.h b/crypto/ecc.h
index 3809dbeb699a..ab0eb70b9c09 100644
--- a/crypto/ecc.h
+++ b/crypto/ecc.h
@@ -26,9 +26,10 @@
#ifndef _CRYPTO_ECC_H
#define _CRYPTO_ECC_H

+/* One digit is u64 qword. */
#define ECC_CURVE_NIST_P192_DIGITS 3
#define ECC_CURVE_NIST_P256_DIGITS 4
-#define ECC_MAX_DIGITS ECC_CURVE_NIST_P256_DIGITS
+#define ECC_MAX_DIGITS (512 / 64)

#define ECC_DIGITS_TO_BYTES_SHIFT 3

@@ -45,6 +46,8 @@ struct ecc_point {
u8 ndigits;
};

+#define ECC_POINT_INIT(x, y, ndigits) (struct ecc_point) { x, y, ndigits }
+
/**
* struct ecc_curve - definition of elliptic curve
*
@@ -180,6 +183,24 @@ u64 vli_sub(u64 *result, const u64 *left, const u64 *right,
unsigned int ndigits);

/**
+ * vli_from_be64() - Load vli from big-endian u64 array
+ *
+ * @dest: destination vli
+ * @src: source array of u64 BE values
+ * @ndigits: length of both vli and array
+ */
+void vli_from_be64(u64 *dest, const void *src, unsigned int ndigits);
+
+/**
+ * vli_from_le64() - Load vli from little-endian u64 array
+ *
+ * @dest: destination vli
+ * @src: source array of u64 LE values
+ * @ndigits: length of both vli and array
+ */
+void vli_from_le64(u64 *dest, const void *src, unsigned int ndigits);
+
+/**
* vli_mod_inv() - Modular inversion
*
* @result: where to write vli number
@@ -190,4 +211,35 @@ u64 vli_sub(u64 *result, const u64 *left, const u64 *right,
void vli_mod_inv(u64 *result, const u64 *input, const u64 *mod,
unsigned int ndigits);

+/**
+ * vli_mod_mult_slow() - Modular multiplication
+ *
+ * @result: where to write result value
+ * @left: vli number to multiply with @right
+ * @right: vli number to multiply with @left
+ * @mod: modulus
+ * @ndigits: length of all vlis
+ *
+ * Note: Assumes that mod is big enough curve order.
+ */
+void vli_mod_mult_slow(u64 *result, const u64 *left, const u64 *right,
+ const u64 *mod, unsigned int ndigits);
+
+/**
+ * ecc_point_mult_shamir() - Add two points multiplied by scalars
+ *
+ * @result: resulting point
+ * @x: scalar to multiply with @p
+ * @p: point to multiply with @x
+ * @y: scalar to multiply with @q
+ * @q: point to multiply with @y
+ * @curve: curve
+ *
+ * Returns result = x * p + x * q over the curve.
+ * This works faster than two multiplications and addition.
+ */
+void ecc_point_mult_shamir(const struct ecc_point *result,
+ const u64 *x, const struct ecc_point *p,
+ const u64 *y, const struct ecc_point *q,
+ const struct ecc_curve *curve);
#endif
diff --git a/crypto/ecrdsa.c b/crypto/ecrdsa.c
new file mode 100644
index 000000000000..7930b37426eb
--- /dev/null
+++ b/crypto/ecrdsa.c
@@ -0,0 +1,299 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Elliptic Curve (Russian) Digital Signature Algorithm for Cryptographic API
+ *
+ * Copyright (c) 2019 Vitaly Chikunov <[email protected]>
+ *
+ * References:
+ * GOST 34.10-2018, GOST R 34.10-2012, RFC 7091, ISO/IEC 14888-3:2018.
+ *
+ * Historical references:
+ * GOST R 34.10-2001, RFC 4357, ISO/IEC 14888-3:2006/Amd 1:2010.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/crypto.h>
+#include <crypto/streebog.h>
+#include <crypto/internal/akcipher.h>
+#include <crypto/akcipher.h>
+#include <linux/oid_registry.h>
+#include "ecrdsa_params.asn1.h"
+#include "ecrdsa_pub_key.asn1.h"
+#include "ecc.h"
+#include "ecrdsa_defs.h"
+
+#define ECRDSA_MAX_SIG_SIZE (2 * 512 / 8)
+#define ECRDSA_MAX_DIGITS (512 / 64)
+
+struct ecrdsa_ctx {
+ enum OID algo_oid; /* overall public key oid */
+ enum OID curve_oid; /* parameter */
+ enum OID digest_oid; /* parameter */
+ const struct ecc_curve *curve; /* curve from oid */
+ unsigned int digest_len; /* parameter (bytes) */
+ const char *digest; /* digest name from oid */
+ unsigned int key_len; /* @key length (bytes) */
+ const char *key; /* raw public key */
+ struct ecc_point pub_key;
+ u64 _pubp[2][ECRDSA_MAX_DIGITS]; /* point storage for @pub_key */
+};
+
+static const struct ecc_curve *get_curve_by_oid(enum OID oid)
+{
+ switch (oid) {
+ case OID_gostCPSignA:
+ case OID_gostTC26Sign256B:
+ return &gost_cp256a;
+ case OID_gostCPSignB:
+ case OID_gostTC26Sign256C:
+ return &gost_cp256b;
+ case OID_gostCPSignC:
+ case OID_gostTC26Sign256D:
+ return &gost_cp256c;
+ case OID_gostTC26Sign512A:
+ return &gost_tc512a;
+ case OID_gostTC26Sign512B:
+ return &gost_tc512b;
+ /* The following two aren't implemented: */
+ case OID_gostTC26Sign256A:
+ case OID_gostTC26Sign512C:
+ default:
+ return NULL;
+ }
+}
+
+static int ecrdsa_verify(struct akcipher_request *req)
+{
+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+ struct ecrdsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ unsigned char sig[ECRDSA_MAX_SIG_SIZE];
+ unsigned char digest[STREEBOG512_DIGEST_SIZE];
+ unsigned int ndigits = req->dst_len / sizeof(u64);
+ u64 r[ECRDSA_MAX_DIGITS]; /* witness (r) */
+ u64 s[ECRDSA_MAX_DIGITS]; /* second part of sig (s) */
+ u64 e[ECRDSA_MAX_DIGITS]; /* h \mod q */
+ u64 *v = e; /* e^{-1} \mod q */
+ u64 z1[ECRDSA_MAX_DIGITS];
+ u64 z2[ECRDSA_MAX_DIGITS];
+ struct ecc_point cc = ECC_POINT_INIT(s, e, ndigits); /* reuse s, e */
+
+ /*
+ * Digest value, digest algorithm, and curve (modulus) should have the
+ * same length (256 or 512 bits), public key and signature should be
+ * twice bigger.
+ */
+ if (!ctx->curve ||
+ !ctx->digest ||
+ !req->src ||
+ !ctx->pub_key.x ||
+ req->dst_len != ctx->digest_len ||
+ req->dst_len != ctx->curve->g.ndigits * sizeof(u64) ||
+ ctx->pub_key.ndigits != ctx->curve->g.ndigits ||
+ req->dst_len * 2 != req->src_len ||
+ WARN_ON(req->src_len > sizeof(sig)) ||
+ WARN_ON(req->dst_len > sizeof(digest)))
+ return -EBADMSG;
+
+ sg_copy_to_buffer(req->src, sg_nents_for_len(req->src, req->src_len),
+ sig, req->src_len);
+ sg_pcopy_to_buffer(req->src,
+ sg_nents_for_len(req->src,
+ req->src_len + req->dst_len),
+ digest, req->dst_len, req->src_len);
+
+ vli_from_be64(s, sig, ndigits);
+ vli_from_be64(r, sig + ndigits * sizeof(u64), ndigits);
+
+ /* Step 1: verify that 0 < r < q, 0 < s < q */
+ if (vli_is_zero(r, ndigits) ||
+ vli_cmp(r, ctx->curve->n, ndigits) == 1 ||
+ vli_is_zero(s, ndigits) ||
+ vli_cmp(s, ctx->curve->n, ndigits) == 1)
+ return -EKEYREJECTED;
+
+ /* Step 2: calculate hash (h) of the message (passed as input) */
+ /* Step 3: calculate e = h \mod q */
+ vli_from_le64(e, digest, ndigits);
+ if (vli_cmp(e, ctx->curve->n, ndigits) == 1)
+ vli_sub(e, e, ctx->curve->n, ndigits);
+ if (vli_is_zero(e, ndigits))
+ e[0] = 1;
+
+ /* Step 4: calculate v = e^{-1} \mod q */
+ vli_mod_inv(v, e, ctx->curve->n, ndigits);
+
+ /* Step 5: calculate z_1 = sv \mod q, z_2 = -rv \mod q */
+ vli_mod_mult_slow(z1, s, v, ctx->curve->n, ndigits);
+ {
+ u64 _r[ECRDSA_MAX_DIGITS];
+
+ vli_sub(_r, ctx->curve->n, r, ndigits);
+ vli_mod_mult_slow(z2, _r, v, ctx->curve->n, ndigits);
+ }
+
+ /* Step 6: calculate point C = z_1P + z_2Q, and R = x_c \mod q */
+ ecc_point_mult_shamir(&cc, z1, &ctx->curve->g, z2, &ctx->pub_key,
+ ctx->curve);
+ if (vli_cmp(cc.x, ctx->curve->n, ndigits) == 1)
+ vli_sub(cc.x, cc.x, ctx->curve->n, ndigits);
+
+ /* Step 7: if R == r signature is valid */
+ if (!vli_cmp(cc.x, r, ndigits))
+ return 0;
+ else
+ return -EKEYREJECTED;
+}
+
+int ecrdsa_param_curve(void *context, size_t hdrlen, unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct ecrdsa_ctx *ctx = context;
+
+ ctx->curve_oid = look_up_OID(value, vlen);
+ if (!ctx->curve_oid)
+ return -EINVAL;
+ ctx->curve = get_curve_by_oid(ctx->curve_oid);
+ return 0;
+}
+
+/* Optional. If present should match expected digest algo OID. */
+int ecrdsa_param_digest(void *context, size_t hdrlen, unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct ecrdsa_ctx *ctx = context;
+ int digest_oid = look_up_OID(value, vlen);
+
+ if (digest_oid != ctx->digest_oid)
+ return -EINVAL;
+ return 0;
+}
+
+int ecrdsa_parse_pub_key(void *context, size_t hdrlen, unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct ecrdsa_ctx *ctx = context;
+
+ ctx->key = value;
+ ctx->key_len = vlen;
+ return 0;
+}
+
+static u8 *ecrdsa_unpack_u32(u32 *dst, void *src)
+{
+ memcpy(dst, src, sizeof(u32));
+ return src + sizeof(u32);
+}
+
+/* Parse BER encoded subjectPublicKey. */
+static int ecrdsa_set_pub_key(struct crypto_akcipher *tfm, const void *key,
+ unsigned int keylen)
+{
+ struct ecrdsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ unsigned int ndigits;
+ u32 algo, paramlen;
+ u8 *params;
+ int err;
+
+ err = asn1_ber_decoder(&ecrdsa_pub_key_decoder, ctx, key, keylen);
+ if (err < 0)
+ return err;
+
+ /* Key parameters is in the key after keylen. */
+ params = ecrdsa_unpack_u32(&paramlen,
+ ecrdsa_unpack_u32(&algo, (u8 *)key + keylen));
+
+ if (algo == OID_gost2012PKey256) {
+ ctx->digest = "streebog256";
+ ctx->digest_oid = OID_gost2012Digest256;
+ ctx->digest_len = 256 / 8;
+ } else if (algo == OID_gost2012PKey512) {
+ ctx->digest = "streebog512";
+ ctx->digest_oid = OID_gost2012Digest512;
+ ctx->digest_len = 512 / 8;
+ } else
+ return -ENOPKG;
+ ctx->algo_oid = algo;
+
+ /* Parse SubjectPublicKeyInfo.AlgorithmIdentifier.parameters. */
+ err = asn1_ber_decoder(&ecrdsa_params_decoder, ctx, params, paramlen);
+ if (err < 0)
+ return err;
+ /*
+ * Sizes of algo (set in digest_len) and curve should match
+ * each other.
+ */
+ if (!ctx->curve ||
+ ctx->curve->g.ndigits * sizeof(u64) != ctx->digest_len)
+ return -ENOPKG;
+ /*
+ * Key is two 256- or 512-bit coordinates which should match
+ * curve size.
+ */
+ if ((ctx->key_len != (2 * 256 / 8) &&
+ ctx->key_len != (2 * 512 / 8)) ||
+ ctx->key_len != ctx->curve->g.ndigits * sizeof(u64) * 2)
+ return -ENOPKG;
+
+ ndigits = ctx->key_len / sizeof(u64) / 2;
+ ctx->pub_key = ECC_POINT_INIT(ctx->_pubp[0], ctx->_pubp[1], ndigits);
+ vli_from_le64(ctx->pub_key.x, ctx->key, ndigits);
+ vli_from_le64(ctx->pub_key.y, ctx->key + ndigits * sizeof(u64),
+ ndigits);
+
+ if (ecc_is_pubkey_valid_partial(ctx->curve, &ctx->pub_key))
+ return -EKEYREJECTED;
+
+ return 0;
+}
+
+static unsigned int ecrdsa_max_size(struct crypto_akcipher *tfm)
+{
+ struct ecrdsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+
+ /*
+ * Verify doesn't need any output, so it's just informational
+ * for keyctl to determine the key bit size.
+ */
+ return ctx->pub_key.ndigits * sizeof(u64);
+}
+
+static void ecrdsa_exit_tfm(struct crypto_akcipher *tfm)
+{
+}
+
+static struct akcipher_alg ecrdsa_alg = {
+ .verify = ecrdsa_verify,
+ .set_pub_key = ecrdsa_set_pub_key,
+ .max_size = ecrdsa_max_size,
+ .exit = ecrdsa_exit_tfm,
+ .base = {
+ .cra_name = "ecrdsa",
+ .cra_driver_name = "ecrdsa-generic",
+ .cra_priority = 100,
+ .cra_module = THIS_MODULE,
+ .cra_ctxsize = sizeof(struct ecrdsa_ctx),
+ },
+};
+
+static int __init ecrdsa_mod_init(void)
+{
+ return crypto_register_akcipher(&ecrdsa_alg);
+}
+
+static void __exit ecrdsa_mod_fini(void)
+{
+ crypto_unregister_akcipher(&ecrdsa_alg);
+}
+
+module_init(ecrdsa_mod_init);
+module_exit(ecrdsa_mod_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Vitaly Chikunov <[email protected]>");
+MODULE_DESCRIPTION("EC-RDSA generic algorithm");
+MODULE_ALIAS_CRYPTO("ecrdsa-generic");
diff --git a/crypto/ecrdsa_defs.h b/crypto/ecrdsa_defs.h
new file mode 100644
index 000000000000..170baf039007
--- /dev/null
+++ b/crypto/ecrdsa_defs.h
@@ -0,0 +1,225 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Definitions of EC-RDSA Curve Parameters
+ *
+ * Copyright (c) 2019 Vitaly Chikunov <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#ifndef _CRYTO_ECRDSA_DEFS_H
+#define _CRYTO_ECRDSA_DEFS_H
+
+#include "ecc.h"
+
+#define ECRDSA_MAX_SIG_SIZE (2 * 512 / 8)
+#define ECRDSA_MAX_DIGITS (512 / 64)
+
+/*
+ * EC-RDSA uses its own set of curves.
+ *
+ * cp256{a,b,c} curves first defined for GOST R 34.10-2001 in RFC 4357 (as
+ * 256-bit {A,B,C}-ParamSet), but inherited for GOST R 34.10-2012 and
+ * proposed for use in R 50.1.114-2016 and RFC 7836 as the 256-bit curves.
+ */
+/* OID_gostCPSignA 1.2.643.2.2.35.1 */
+static u64 cp256a_g_x[] = {
+ 0x0000000000000001ull, 0x0000000000000000ull,
+ 0x0000000000000000ull, 0x0000000000000000ull, };
+static u64 cp256a_g_y[] = {
+ 0x22ACC99C9E9F1E14ull, 0x35294F2DDF23E3B1ull,
+ 0x27DF505A453F2B76ull, 0x8D91E471E0989CDAull, };
+static u64 cp256a_p[] = { /* p = 2^256 - 617 */
+ 0xFFFFFFFFFFFFFD97ull, 0xFFFFFFFFFFFFFFFFull,
+ 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull };
+static u64 cp256a_n[] = {
+ 0x45841B09B761B893ull, 0x6C611070995AD100ull,
+ 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull };
+static u64 cp256a_a[] = { /* a = p - 3 */
+ 0xFFFFFFFFFFFFFD94ull, 0xFFFFFFFFFFFFFFFFull,
+ 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull };
+static u64 cp256a_b[] = {
+ 0x00000000000000a6ull, 0x0000000000000000ull,
+ 0x0000000000000000ull, 0x0000000000000000ull };
+
+static struct ecc_curve gost_cp256a = {
+ .name = "cp256a",
+ .g = {
+ .x = cp256a_g_x,
+ .y = cp256a_g_y,
+ .ndigits = 256 / 64,
+ },
+ .p = cp256a_p,
+ .n = cp256a_n,
+ .a = cp256a_a,
+ .b = cp256a_b
+};
+
+/* OID_gostCPSignB 1.2.643.2.2.35.2 */
+static u64 cp256b_g_x[] = {
+ 0x0000000000000001ull, 0x0000000000000000ull,
+ 0x0000000000000000ull, 0x0000000000000000ull, };
+static u64 cp256b_g_y[] = {
+ 0x744BF8D717717EFCull, 0xC545C9858D03ECFBull,
+ 0xB83D1C3EB2C070E5ull, 0x3FA8124359F96680ull, };
+static u64 cp256b_p[] = { /* p = 2^255 + 3225 */
+ 0x0000000000000C99ull, 0x0000000000000000ull,
+ 0x0000000000000000ull, 0x8000000000000000ull, };
+static u64 cp256b_n[] = {
+ 0xE497161BCC8A198Full, 0x5F700CFFF1A624E5ull,
+ 0x0000000000000001ull, 0x8000000000000000ull, };
+static u64 cp256b_a[] = { /* a = p - 3 */
+ 0x0000000000000C96ull, 0x0000000000000000ull,
+ 0x0000000000000000ull, 0x8000000000000000ull, };
+static u64 cp256b_b[] = {
+ 0x2F49D4CE7E1BBC8Bull, 0xE979259373FF2B18ull,
+ 0x66A7D3C25C3DF80Aull, 0x3E1AF419A269A5F8ull, };
+
+static struct ecc_curve gost_cp256b = {
+ .name = "cp256b",
+ .g = {
+ .x = cp256b_g_x,
+ .y = cp256b_g_y,
+ .ndigits = 256 / 64,
+ },
+ .p = cp256b_p,
+ .n = cp256b_n,
+ .a = cp256b_a,
+ .b = cp256b_b
+};
+
+/* OID_gostCPSignC 1.2.643.2.2.35.3 */
+static u64 cp256c_g_x[] = {
+ 0x0000000000000000ull, 0x0000000000000000ull,
+ 0x0000000000000000ull, 0x0000000000000000ull, };
+static u64 cp256c_g_y[] = {
+ 0x366E550DFDB3BB67ull, 0x4D4DC440D4641A8Full,
+ 0x3CBF3783CD08C0EEull, 0x41ECE55743711A8Cull, };
+static u64 cp256c_p[] = {
+ 0x7998F7B9022D759Bull, 0xCF846E86789051D3ull,
+ 0xAB1EC85E6B41C8AAull, 0x9B9F605F5A858107ull,
+ /* pre-computed value for Barrett's reduction */
+ 0xedc283cdd217b5a2ull, 0xbac48fc06398ae59ull,
+ 0x405384d55f9f3b73ull, 0xa51f176161f1d734ull,
+ 0x0000000000000001ull, };
+static u64 cp256c_n[] = {
+ 0xF02F3A6598980BB9ull, 0x582CA3511EDDFB74ull,
+ 0xAB1EC85E6B41C8AAull, 0x9B9F605F5A858107ull, };
+static u64 cp256c_a[] = { /* a = p - 3 */
+ 0x7998F7B9022D7598ull, 0xCF846E86789051D3ull,
+ 0xAB1EC85E6B41C8AAull, 0x9B9F605F5A858107ull, };
+static u64 cp256c_b[] = {
+ 0x000000000000805aull, 0x0000000000000000ull,
+ 0x0000000000000000ull, 0x0000000000000000ull, };
+
+static struct ecc_curve gost_cp256c = {
+ .name = "cp256c",
+ .g = {
+ .x = cp256c_g_x,
+ .y = cp256c_g_y,
+ .ndigits = 256 / 64,
+ },
+ .p = cp256c_p,
+ .n = cp256c_n,
+ .a = cp256c_a,
+ .b = cp256c_b
+};
+
+/* tc512{a,b} curves first recommended in 2013 and then standardized in
+ * R 50.1.114-2016 and RFC 7836 for use with GOST R 34.10-2012 (as TC26
+ * 512-bit ParamSet{A,B}).
+ */
+/* OID_gostTC26Sign512A 1.2.643.7.1.2.1.2.1 */
+static u64 tc512a_g_x[] = {
+ 0x0000000000000003ull, 0x0000000000000000ull,
+ 0x0000000000000000ull, 0x0000000000000000ull,
+ 0x0000000000000000ull, 0x0000000000000000ull,
+ 0x0000000000000000ull, 0x0000000000000000ull, };
+static u64 tc512a_g_y[] = {
+ 0x89A589CB5215F2A4ull, 0x8028FE5FC235F5B8ull,
+ 0x3D75E6A50E3A41E9ull, 0xDF1626BE4FD036E9ull,
+ 0x778064FDCBEFA921ull, 0xCE5E1C93ACF1ABC1ull,
+ 0xA61B8816E25450E6ull, 0x7503CFE87A836AE3ull, };
+static u64 tc512a_p[] = { /* p = 2^512 - 569 */
+ 0xFFFFFFFFFFFFFDC7ull, 0xFFFFFFFFFFFFFFFFull,
+ 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
+ 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
+ 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, };
+static u64 tc512a_n[] = {
+ 0xCACDB1411F10B275ull, 0x9B4B38ABFAD2B85Dull,
+ 0x6FF22B8D4E056060ull, 0x27E69532F48D8911ull,
+ 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
+ 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, };
+static u64 tc512a_a[] = { /* a = p - 3 */
+ 0xFFFFFFFFFFFFFDC4ull, 0xFFFFFFFFFFFFFFFFull,
+ 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
+ 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull,
+ 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull, };
+static u64 tc512a_b[] = {
+ 0x503190785A71C760ull, 0x862EF9D4EBEE4761ull,
+ 0x4CB4574010DA90DDull, 0xEE3CB090F30D2761ull,
+ 0x79BD081CFD0B6265ull, 0x34B82574761CB0E8ull,
+ 0xC1BD0B2B6667F1DAull, 0xE8C2505DEDFC86DDull, };
+
+static struct ecc_curve gost_tc512a = {
+ .name = "tc512a",
+ .g = {
+ .x = tc512a_g_x,
+ .y = tc512a_g_y,
+ .ndigits = 512 / 64,
+ },
+ .p = tc512a_p,
+ .n = tc512a_n,
+ .a = tc512a_a,
+ .b = tc512a_b
+};
+
+/* OID_gostTC26Sign512B 1.2.643.7.1.2.1.2.2 */
+static u64 tc512b_g_x[] = {
+ 0x0000000000000002ull, 0x0000000000000000ull,
+ 0x0000000000000000ull, 0x0000000000000000ull,
+ 0x0000000000000000ull, 0x0000000000000000ull,
+ 0x0000000000000000ull, 0x0000000000000000ull, };
+static u64 tc512b_g_y[] = {
+ 0x7E21340780FE41BDull, 0x28041055F94CEEECull,
+ 0x152CBCAAF8C03988ull, 0xDCB228FD1EDF4A39ull,
+ 0xBE6DD9E6C8EC7335ull, 0x3C123B697578C213ull,
+ 0x2C071E3647A8940Full, 0x1A8F7EDA389B094Cull, };
+static u64 tc512b_p[] = { /* p = 2^511 + 111 */
+ 0x000000000000006Full, 0x0000000000000000ull,
+ 0x0000000000000000ull, 0x0000000000000000ull,
+ 0x0000000000000000ull, 0x0000000000000000ull,
+ 0x0000000000000000ull, 0x8000000000000000ull, };
+static u64 tc512b_n[] = {
+ 0xC6346C54374F25BDull, 0x8B996712101BEA0Eull,
+ 0xACFDB77BD9D40CFAull, 0x49A1EC142565A545ull,
+ 0x0000000000000001ull, 0x0000000000000000ull,
+ 0x0000000000000000ull, 0x8000000000000000ull, };
+static u64 tc512b_a[] = { /* a = p - 3 */
+ 0x000000000000006Cull, 0x0000000000000000ull,
+ 0x0000000000000000ull, 0x0000000000000000ull,
+ 0x0000000000000000ull, 0x0000000000000000ull,
+ 0x0000000000000000ull, 0x8000000000000000ull, };
+static u64 tc512b_b[] = {
+ 0xFB8CCBC7C5140116ull, 0x50F78BEE1FA3106Eull,
+ 0x7F8B276FAD1AB69Cull, 0x3E965D2DB1416D21ull,
+ 0xBF85DC806C4B289Full, 0xB97C7D614AF138BCull,
+ 0x7E3E06CF6F5E2517ull, 0x687D1B459DC84145ull, };
+
+static struct ecc_curve gost_tc512b = {
+ .name = "tc512b",
+ .g = {
+ .x = tc512b_g_x,
+ .y = tc512b_g_y,
+ .ndigits = 512 / 64,
+ },
+ .p = tc512b_p,
+ .n = tc512b_n,
+ .a = tc512b_a,
+ .b = tc512b_b
+};
+
+#endif
diff --git a/crypto/ecrdsa_params.asn1 b/crypto/ecrdsa_params.asn1
new file mode 100644
index 000000000000..aba99c3763cf
--- /dev/null
+++ b/crypto/ecrdsa_params.asn1
@@ -0,0 +1,4 @@
+EcrdsaParams ::= SEQUENCE {
+ curve OBJECT IDENTIFIER ({ ecrdsa_param_curve }),
+ digest OBJECT IDENTIFIER OPTIONAL ({ ecrdsa_param_digest })
+}
diff --git a/crypto/ecrdsa_pub_key.asn1 b/crypto/ecrdsa_pub_key.asn1
new file mode 100644
index 000000000000..048cb646bce4
--- /dev/null
+++ b/crypto/ecrdsa_pub_key.asn1
@@ -0,0 +1 @@
+EcrdsaPubKey ::= OCTET STRING ({ ecrdsa_parse_pub_key })
diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h
index d2fa9ca42e9a..7f30446348c4 100644
--- a/include/linux/oid_registry.h
+++ b/include/linux/oid_registry.h
@@ -93,6 +93,24 @@ enum OID {
OID_authorityKeyIdentifier, /* 2.5.29.35 */
OID_extKeyUsage, /* 2.5.29.37 */

+ /* EC-RDSA */
+ OID_gostCPSignA, /* 1.2.643.2.2.35.1 */
+ OID_gostCPSignB, /* 1.2.643.2.2.35.2 */
+ OID_gostCPSignC, /* 1.2.643.2.2.35.3 */
+ OID_gost2012PKey256, /* 1.2.643.7.1.1.1.1 */
+ OID_gost2012PKey512, /* 1.2.643.7.1.1.1.2 */
+ OID_gost2012Digest256, /* 1.2.643.7.1.1.2.2 */
+ OID_gost2012Digest512, /* 1.2.643.7.1.1.2.3 */
+ OID_gost2012Signature256, /* 1.2.643.7.1.1.3.2 */
+ OID_gost2012Signature512, /* 1.2.643.7.1.1.3.3 */
+ OID_gostTC26Sign256A, /* 1.2.643.7.1.2.1.1.1 */
+ OID_gostTC26Sign256B, /* 1.2.643.7.1.2.1.1.2 */
+ OID_gostTC26Sign256C, /* 1.2.643.7.1.2.1.1.3 */
+ OID_gostTC26Sign256D, /* 1.2.643.7.1.2.1.1.4 */
+ OID_gostTC26Sign512A, /* 1.2.643.7.1.2.1.2.1 */
+ OID_gostTC26Sign512B, /* 1.2.643.7.1.2.1.2.2 */
+ OID_gostTC26Sign512C, /* 1.2.643.7.1.2.1.2.3 */
+
OID__NR
};

--
2.11.0


2019-03-01 18:00:08

by Vitaly Chikunov

[permalink] [raw]
Subject: [PATCH v7 11/11] integrity: support EC-RDSA signatures for asymmetric_verify

Allow to use EC-RDSA signatures for IMA by determining signature type by
the hash algorithm name. This works good for EC-RDSA since Streebog and
EC-RDSA should always be used together.

Cc: Mimi Zohar <[email protected]>
Cc: Dmitry Kasatkin <[email protected]>
Cc: [email protected]
Signed-off-by: Vitaly Chikunov <[email protected]>
---
security/integrity/digsig_asymmetric.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
index d775e03fbbcc..99080871eb9f 100644
--- a/security/integrity/digsig_asymmetric.c
+++ b/security/integrity/digsig_asymmetric.c
@@ -104,9 +104,16 @@ int asymmetric_verify(struct key *keyring, const char *sig,

memset(&pks, 0, sizeof(pks));

- pks.pkey_algo = "rsa";
pks.hash_algo = hash_algo_name[hdr->hash_algo];
- pks.encoding = "pkcs1";
+ if (hdr->hash_algo == HASH_ALGO_STREEBOG_256 ||
+ hdr->hash_algo == HASH_ALGO_STREEBOG_512) {
+ /* EC-RDSA and Streebog should go together. */
+ pks.pkey_algo = "ecrdsa";
+ pks.encoding = "raw";
+ } else {
+ pks.pkey_algo = "rsa";
+ pks.encoding = "pkcs1";
+ }
pks.digest = (u8 *)data;
pks.digest_size = datalen;
pks.s = hdr->sig;
--
2.11.0


2019-03-01 18:00:09

by Vitaly Chikunov

[permalink] [raw]
Subject: [PATCH v7 10/11] crypto: ecrdsa - add EC-RDSA test vectors to testmgr

Add testmgr test vectors for EC-RDSA algorithm for every of five
supported parameters (curves). Because there are no officially published
test vectors for the curves, the vectors are generated by gost-engine.

Signed-off-by: Vitaly Chikunov <[email protected]>
---
crypto/testmgr.c | 6 +++
crypto/testmgr.h | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 160 insertions(+)

diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 50396b3a2a47..d675755ef13f 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -3384,6 +3384,12 @@ static const struct alg_test_desc alg_test_descs[] = {
.kpp = __VECS(ecdh_tv_template)
}
}, {
+ .alg = "ecrdsa",
+ .test = alg_test_akcipher,
+ .suite = {
+ .akcipher = __VECS(ecrdsa_tv_template)
+ }
+ }, {
.alg = "gcm(aes)",
.test = alg_test_aead,
.fips_allowed = 1,
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index 75d8f8c3e203..120531b0a86d 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -556,6 +556,160 @@ static const struct akcipher_testvec rsa_tv_template[] = {
};

/*
+ * EC-RDSA test vectors are generated by gost-engine.
+ */
+static const struct akcipher_testvec ecrdsa_tv_template[] = {
+ {
+ .key =
+ "\x04\x40\xd5\xa7\x77\xf9\x26\x2f\x8c\xbd\xcc\xe3\x1f\x01\x94\x05"
+ "\x3d\x2f\xec\xb5\x00\x34\xf5\x51\x6d\x3b\x90\x4b\x23\x28\x6f\x1d"
+ "\xc8\x36\x61\x60\x36\xec\xbb\xb4\x0b\x95\x4e\x54\x4f\x15\x21\x05"
+ "\xd8\x52\x66\x44\x31\x7e\x5d\xc5\xd1\x26\x00\x5f\x60\xd8\xf0\xc7"
+ "\x27\xfc",
+ .key_len = 66,
+ .params = /* OID_gostCPSignA */
+ "\x30\x13\x06\x07\x2a\x85\x03\x02\x02\x23\x01\x06\x08\x2a\x85\x03"
+ "\x07\x01\x01\x02\x02",
+ .param_len = 21,
+ .c =
+ "\x41\x32\x09\x73\xa4\xc1\x38\xd6\x63\x7d\x8b\xf7\x50\x3f\xda\x9f"
+ "\x68\x48\xc1\x50\xe3\x42\x3a\x9b\x2b\x28\x12\x2a\xa7\xc2\x75\x31"
+ "\x65\x77\x8c\x3c\x9e\x0d\x56\xb2\xf9\xdc\x04\x33\x3e\xb0\x9e\xf9"
+ "\x74\x4e\x59\xb3\x83\xf2\x91\x27\xda\x5e\xc7\x33\xc0\xc1\x8f\x41",
+ .c_size = 64,
+ .algo = OID_gost2012PKey256,
+ .m =
+ "\x75\x1b\x9b\x40\x25\xb9\x96\xd2\x9b\x00\x41\xb3\x58\xbf\x23\x14"
+ "\x79\xd2\x76\x64\xa3\xbd\x66\x10\x79\x05\x5a\x06\x42\xec\xb9\xc9",
+ .m_size = 32,
+ .public_key_vec = true,
+ .siggen_sigver_test = true,
+ },
+ {
+ .key =
+ "\x04\x40\x66\x6f\xd6\xb7\x06\xd0\xf5\xa5\x6f\x69\x5c\xa5\x13\x45"
+ "\x14\xdd\xcb\x12\x9c\x1b\xf5\x28\x64\x7a\x49\x48\x29\x14\x66\x42"
+ "\xb8\x1b\x5c\xf9\x56\x6d\x08\x3b\xce\xbb\x62\x2f\xc2\x3c\xc5\x49"
+ "\x93\x27\x70\x20\xcc\x79\xeb\xdc\x76\x8e\x48\x6e\x04\x96\xc3\x29"
+ "\xa0\x73",
+ .key_len = 66,
+ .params = /* OID_gostCPSignB */
+ "\x30\x13\x06\x07\x2a\x85\x03\x02\x02\x23\x02\x06\x08\x2a\x85\x03"
+ "\x07\x01\x01\x02\x02",
+ .param_len = 21,
+ .c =
+ "\x45\x6d\x4a\x03\x1d\x5c\x0b\x17\x79\xe7\x19\xdb\xbf\x81\x9f\x82"
+ "\xae\x06\xda\xf5\x47\x00\x05\x80\xc3\x16\x06\x9a\x8e\x7c\xb2\x8e"
+ "\x7f\x74\xaa\xec\x6b\x7b\x7f\x8b\xc6\x0b\x10\x42\x4e\x91\x2c\xdf"
+ "\x7b\x8b\x15\xf4\x9e\x59\x0f\xc7\xa4\x68\x2e\xce\x89\xdf\x84\xe9",
+ .c_size = 64,
+ .algo = OID_gost2012PKey256,
+ .m =
+ "\xd0\x54\x00\x27\x6a\xeb\xce\x6c\xf5\xf6\xfb\x57\x18\x18\x21\x13"
+ "\x11\x23\x4a\x70\x43\x52\x7a\x68\x11\x65\x45\x37\xbb\x25\xb7\x40",
+ .m_size = 32,
+ .public_key_vec = true,
+ .siggen_sigver_test = true,
+ },
+ {
+ .key =
+ "\x04\x40\x05\x91\xa9\x7d\xcb\x87\xdc\x98\xa1\xbf\xff\xdd\x20\x61"
+ "\xaa\x58\x3b\x2d\x8e\x9c\x41\x9d\x4f\xc6\x23\x17\xf9\xca\x60\x65"
+ "\xbc\x97\x97\xf6\x6b\x24\xe8\xac\xb1\xa7\x61\x29\x3c\x71\xdc\xad"
+ "\xcb\x20\xbe\x96\xe8\xf4\x44\x2e\x49\xd5\x2c\xb9\xc9\x3b\x9c\xaa"
+ "\xba\x15",
+ .key_len = 66,
+ .params = /* OID_gostCPSignC */
+ "\x30\x13\x06\x07\x2a\x85\x03\x02\x02\x23\x03\x06\x08\x2a\x85\x03"
+ "\x07\x01\x01\x02\x02",
+ .param_len = 21,
+ .c =
+ "\x3b\x2e\x2e\x74\x74\x47\xda\xea\x93\x90\x6a\xe2\xf5\xf5\xe6\x46"
+ "\x11\xfc\xab\xdc\x52\xbc\x58\xdb\x45\x44\x12\x4a\xf7\xd0\xab\xc9"
+ "\x73\xba\x64\xab\x0d\xac\x4e\x72\x10\xa8\x04\xf6\x1e\xe0\x48\x6a"
+ "\xcd\xe8\xe3\x78\x73\x77\x82\x24\x8d\xf1\xd3\xeb\x4c\x25\x7e\xc0",
+ .c_size = 64,
+ .algo = OID_gost2012PKey256,
+ .m =
+ "\x52\x33\xf4\x3f\x7b\x5d\xcf\x20\xee\xe4\x5c\xab\x0b\x3f\x14\xd6"
+ "\x9f\x16\xc6\x1c\xb1\x3f\x84\x41\x69\xec\x34\xfd\xf1\xf9\xa3\x39",
+ .m_size = 32,
+ .public_key_vec = true,
+ .siggen_sigver_test = true,
+ },
+ {
+ .key =
+ "\x04\x81\x80\x85\x46\x8f\x16\xf8\x7a\x7e\x4a\xc3\x81\x9e\xf1\x6e"
+ "\x94\x1e\x5d\x02\x87\xea\xfa\xa0\x0a\x17\x70\x49\x64\xad\x95\x68"
+ "\x60\x0a\xf0\x57\x29\x41\x79\x30\x3c\x61\x69\xf2\xa6\x94\x87\x17"
+ "\x54\xfa\x97\x2c\xe6\x1e\x0a\xbb\x55\x10\x57\xbe\xf7\xc1\x77\x2b"
+ "\x11\x74\x0a\x50\x37\x14\x10\x2a\x45\xfc\x7a\xae\x1c\x4c\xce\x08"
+ "\x05\xb7\xa4\x50\xc8\x3d\x39\x3d\xdc\x5c\x8f\x96\x6c\xe7\xfc\x21"
+ "\xc3\x2d\x1e\x9f\x11\xb3\xec\x22\x18\x8a\x8c\x08\x6b\x8b\xed\xf5"
+ "\xc5\x47\x3c\x7e\x73\x59\x44\x1e\x77\x83\x84\x52\x9e\x3b\x7d\xff"
+ "\x9d\x86\x1a",
+ .key_len = 131,
+ .params = /* OID_gostTC26Sign512A */
+ "\x30\x0b\x06\x09\x2a\x85\x03\x07\x01\x02\x01\x02\x01",
+ .param_len = 13,
+ .c =
+ "\x92\x81\x74\x5f\x95\x48\x38\x87\xd9\x8f\x5e\xc8\x8a\xbb\x01\x4e"
+ "\xb0\x75\x3c\x2f\xc7\x5a\x08\x4c\x68\xab\x75\x01\x32\x75\x75\xb5"
+ "\x37\xe0\x74\x6d\x94\x84\x31\x2a\x6b\xf4\xf7\xb7\xa7\x39\x7b\x46"
+ "\x07\xf0\x98\xbd\x33\x18\xa1\x72\xb2\x6d\x54\xe3\xde\x91\xc2\x2e"
+ "\x4f\x6a\xf8\xb7\xec\xa8\x83\xc9\x8f\xd9\xce\x7c\x45\x06\x02\xf4"
+ "\x4f\x21\xb5\x24\x3d\xb4\xb5\xd8\x58\x42\xbe\x2d\x29\xae\x93\xc0"
+ "\x13\x41\x96\x35\x08\x69\xe8\x36\xc7\xd1\x83\x81\xd7\xca\xfb\xc0"
+ "\xd2\xb7\x78\x32\x3e\x30\x1a\x1e\xce\xdc\x34\x35\xc6\xad\x68\x24",
+ .c_size = 128,
+ .algo = OID_gost2012PKey512,
+ .m =
+ "\x1f\x70\xb5\xe9\x55\x12\xd6\x88\xcc\x55\xb9\x0c\x7f\xc4\x94\xf2"
+ "\x04\x77\x41\x12\x02\xd6\xf1\x1f\x83\x56\xe9\xd6\x5a\x6a\x72\xb9"
+ "\x6e\x8e\x24\x2a\x84\xf1\xba\x67\xe8\xbf\xff\xc1\xd3\xde\xfb\xc6"
+ "\xa8\xf6\x80\x01\xb9\x27\xac\xd8\x45\x96\x66\xa1\xee\x48\x08\x3f",
+ .m_size = 64,
+ .public_key_vec = true,
+ .siggen_sigver_test = true,
+ },
+ {
+ .key =
+ "\x04\x81\x80\x28\xf3\x2b\x92\x04\x32\xea\x66\x20\xde\xa0\x2f\x74"
+ "\xbf\x2d\xf7\xb5\x30\x76\xb1\xc8\xee\x38\x9f\xea\xe5\xad\xc6\xa3"
+ "\x28\x1e\x51\x3d\x67\xa3\x41\xcc\x6b\x81\xe2\xe2\x9e\x82\xf3\x78"
+ "\x56\xd7\x2e\xb2\xb5\xbe\xb4\x50\x21\x05\xe5\x29\x82\xef\x15\x1b"
+ "\xc0\xd7\x30\xd6\x2f\x96\xe8\xff\x99\x4c\x25\xcf\x9a\xfc\x54\x30"
+ "\xce\xdf\x59\xe9\xc6\x45\xce\xe4\x22\xe8\x01\xd5\xcd\x2f\xaa\x78"
+ "\x99\xc6\x04\x1e\x6f\x4c\x25\x6a\x76\xad\xff\x48\xf3\xb3\xb4\xd6"
+ "\x14\x5c\x2c\x0e\xea\xa2\x4b\xb9\x7e\x89\x77\x02\x3a\x29\xc8\x16"
+ "\x8e\x78\x48",
+ .key_len = 131,
+ .params = /* OID_gostTC26Sign512B */
+ "\x30\x0b\x06\x09\x2a\x85\x03\x07\x01\x02\x01\x02\x02",
+ .param_len = 13,
+ .c =
+ "\x0a\xed\xb6\x27\xea\xa7\xa6\x7e\x2f\xc1\x02\x21\x74\xce\x27\xd2"
+ "\xee\x8a\x92\x4d\xa9\x43\x2d\xa4\x5b\xdc\x23\x02\xfc\x3a\xf3\xb2"
+ "\x10\x93\x0b\x40\x1b\x75\x95\x3e\x39\x41\x37\xb9\xab\x51\x09\xeb"
+ "\xf1\xb9\x49\x58\xec\x58\xc7\xf9\x2e\xb9\xc9\x40\xf2\x00\x39\x7e"
+ "\x3f\xde\x72\xe3\x85\x67\x06\xbe\xd8\xb8\xc1\x81\x1e\xe3\x0a\xfe"
+ "\xce\xd3\x77\x92\x56\x8c\x58\xf9\x37\x60\x2d\xe6\x8b\x66\xa3\xdd"
+ "\xd2\xf0\xf8\xda\x1b\x20\xbc\x9c\xec\x29\x5d\xd1\x8f\xcc\x37\xd1"
+ "\x3b\x8d\xb7\xc1\xe0\xb8\x3b\xef\x14\x1b\x87\xbc\xc1\x03\x9a\x93",
+ .c_size = 128,
+ .algo = OID_gost2012PKey512,
+ .m =
+ "\x11\x24\x21\x27\xf2\x42\x9f\xce\x5a\xf9\x01\x70\xe0\x07\x2b\x57"
+ "\xfb\x7d\x77\x5e\x74\x66\xe6\xa5\x40\x4c\x1a\x85\x18\xff\xd0\x63"
+ "\xe0\x39\xd3\xd6\xe5\x17\xf8\xc3\x4b\xc6\x1c\x33\x1a\xca\xa6\x66"
+ "\x6d\xf4\xd2\x45\xc2\x83\xa0\x42\x95\x05\x9d\x89\x8e\x0a\xca\xcc",
+ .m_size = 64,
+ .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[] = {
--
2.11.0


2019-03-01 18:00:21

by Vitaly Chikunov

[permalink] [raw]
Subject: [PATCH v7 08/11] crypto: ecc - make ecc into separate module

ecc.c have algorithms that could be used togeter by ecdh and ecrdsa.
Make it separate module. Add CRYPTO_ECC into Kconfig. EXPORT_SYMBOL and
document to what seems appropriate. Move structs ecc_point and ecc_curve
from ecc_curve_defs.h into ecc.h.

No code changes.

Signed-off-by: Vitaly Chikunov <[email protected]>
---
crypto/Kconfig | 4 ++
crypto/Makefile | 2 +-
crypto/ecc.c | 25 +++++++++----
crypto/ecc.h | 99 +++++++++++++++++++++++++++++++++++++++++++++++++
crypto/ecc_curve_defs.h | 15 --------
5 files changed, 122 insertions(+), 23 deletions(-)

diff --git a/crypto/Kconfig b/crypto/Kconfig
index 370cbdca87a7..cf0bceee0ea5 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -248,8 +248,12 @@ config CRYPTO_DH
help
Generic implementation of the Diffie-Hellman algorithm.

+config CRYPTO_ECC
+ tristate
+
config CRYPTO_ECDH
tristate "ECDH algorithm"
+ select CRYPTO_ECC
select CRYPTO_KPP
select CRYPTO_RNG_DEFAULT
help
diff --git a/crypto/Makefile b/crypto/Makefile
index 799ed5e94606..b660f078651a 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -147,8 +147,8 @@ obj-$(CONFIG_CRYPTO_USER_API_RNG) += algif_rng.o
obj-$(CONFIG_CRYPTO_USER_API_AEAD) += algif_aead.o
obj-$(CONFIG_CRYPTO_ZSTD) += zstd.o
obj-$(CONFIG_CRYPTO_OFB) += ofb.o
+obj-$(CONFIG_CRYPTO_ECC) += ecc.o

-ecdh_generic-y := ecc.o
ecdh_generic-y += ecdh.o
ecdh_generic-y += ecdh_helper.o
obj-$(CONFIG_CRYPTO_ECDH) += ecdh_generic.o
diff --git a/crypto/ecc.c b/crypto/ecc.c
index ed1237115066..5f36792d143d 100644
--- a/crypto/ecc.c
+++ b/crypto/ecc.c
@@ -24,6 +24,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

+#include <linux/module.h>
#include <linux/random.h>
#include <linux/slab.h>
#include <linux/swab.h>
@@ -112,7 +113,7 @@ static void vli_clear(u64 *vli, unsigned int ndigits)
}

/* Returns true if vli == 0, false otherwise. */
-static bool vli_is_zero(const u64 *vli, unsigned int ndigits)
+bool vli_is_zero(const u64 *vli, unsigned int ndigits)
{
int i;

@@ -123,6 +124,7 @@ static bool vli_is_zero(const u64 *vli, unsigned int ndigits)

return true;
}
+EXPORT_SYMBOL(vli_is_zero);

/* Returns nonzero if bit bit of vli is set. */
static u64 vli_test_bit(const u64 *vli, unsigned int bit)
@@ -171,7 +173,7 @@ static void vli_set(u64 *dest, const u64 *src, unsigned int ndigits)
}

/* Returns sign of left - right. */
-static int vli_cmp(const u64 *left, const u64 *right, unsigned int ndigits)
+int vli_cmp(const u64 *left, const u64 *right, unsigned int ndigits)
{
int i;

@@ -184,6 +186,7 @@ static int vli_cmp(const u64 *left, const u64 *right, unsigned int ndigits)

return 0;
}
+EXPORT_SYMBOL(vli_cmp);

/* Computes result = in << c, returning carry. Can modify in place
* (if result == in). 0 < shift < 64.
@@ -240,7 +243,7 @@ static u64 vli_add(u64 *result, const u64 *left, const u64 *right,
}

/* Computes result = left - right, returning borrow. Can modify in place. */
-static u64 vli_sub(u64 *result, const u64 *left, const u64 *right,
+u64 vli_sub(u64 *result, const u64 *left, const u64 *right,
unsigned int ndigits)
{
u64 borrow = 0;
@@ -258,6 +261,7 @@ static u64 vli_sub(u64 *result, const u64 *left, const u64 *right,

return borrow;
}
+EXPORT_SYMBOL(vli_sub);

static uint128_t mul_64_64(u64 left, u64 right)
{
@@ -557,7 +561,7 @@ static void vli_mod_square_fast(u64 *result, const u64 *left,
* See "From Euclid's GCD to Montgomery Multiplication to the Great Divide"
* https://labs.oracle.com/techrep/2001/smli_tr-2001-95.pdf
*/
-static void vli_mod_inv(u64 *result, const u64 *input, const u64 *mod,
+void vli_mod_inv(u64 *result, const u64 *input, const u64 *mod,
unsigned int ndigits)
{
u64 a[ECC_MAX_DIGITS], b[ECC_MAX_DIGITS];
@@ -630,6 +634,7 @@ static void vli_mod_inv(u64 *result, const u64 *input, const u64 *mod,

vli_set(result, u, ndigits);
}
+EXPORT_SYMBOL(vli_mod_inv);

/* ------ Point operations ------ */

@@ -948,6 +953,7 @@ int ecc_is_key_valid(unsigned int curve_id, unsigned int ndigits,

return __ecc_is_key_valid(curve, private_key, ndigits);
}
+EXPORT_SYMBOL(ecc_is_key_valid);

/*
* ECC private keys are generated using the method of extra random bits,
@@ -1000,6 +1006,7 @@ int ecc_gen_privkey(unsigned int curve_id, unsigned int ndigits, u64 *privkey)

return 0;
}
+EXPORT_SYMBOL(ecc_gen_privkey);

int ecc_make_pub_key(unsigned int curve_id, unsigned int ndigits,
const u64 *private_key, u64 *public_key)
@@ -1036,10 +1043,11 @@ int ecc_make_pub_key(unsigned int curve_id, unsigned int ndigits,
out:
return ret;
}
+EXPORT_SYMBOL(ecc_make_pub_key);

/* SP800-56A section 5.6.2.3.4 partial verification: ephemeral keys only */
-static int ecc_is_pubkey_valid_partial(const struct ecc_curve *curve,
- struct ecc_point *pk)
+int ecc_is_pubkey_valid_partial(const struct ecc_curve *curve,
+ struct ecc_point *pk)
{
u64 yy[ECC_MAX_DIGITS], xxx[ECC_MAX_DIGITS], w[ECC_MAX_DIGITS];

@@ -1064,8 +1072,8 @@ static int ecc_is_pubkey_valid_partial(const struct ecc_curve *curve,
return -EINVAL;

return 0;
-
}
+EXPORT_SYMBOL(ecc_is_pubkey_valid_partial);

int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits,
const u64 *private_key, const u64 *public_key,
@@ -1121,3 +1129,6 @@ int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits,
out:
return ret;
}
+EXPORT_SYMBOL(crypto_ecdh_shared_secret);
+
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/crypto/ecc.h b/crypto/ecc.h
index f75a86baa3bd..3809dbeb699a 100644
--- a/crypto/ecc.h
+++ b/crypto/ecc.h
@@ -33,6 +33,41 @@
#define ECC_DIGITS_TO_BYTES_SHIFT 3

/**
+ * struct ecc_point - elliptic curve point in affine coordinates
+ *
+ * @x: X coordinate in vli form.
+ * @y: Y coordinate in vli form.
+ * @ndigits: Length of vlis in u64 qwords.
+ */
+struct ecc_point {
+ u64 *x;
+ u64 *y;
+ u8 ndigits;
+};
+
+/**
+ * struct ecc_curve - definition of elliptic curve
+ *
+ * @name: Short name of the curve.
+ * @g: Generator point of the curve.
+ * @p: Prime number, if Barrett's reduction is used for this curve
+ * pre-calculated value 'mu' is appended to the @p after ndigits.
+ * Use of Barrett's reduction is heuristically determined in
+ * vli_mmod_fast().
+ * @n: Order of the curve group.
+ * @a: Curve parameter a.
+ * @b: Curve parameter b.
+ */
+struct ecc_curve {
+ char *name;
+ struct ecc_point g;
+ u64 *p;
+ u64 *n;
+ u64 *a;
+ u64 *b;
+};
+
+/**
* ecc_is_key_valid() - Validate a given ECDH private key
*
* @curve_id: id representing the curve to use
@@ -91,4 +126,68 @@ int ecc_make_pub_key(const unsigned int curve_id, unsigned int ndigits,
int crypto_ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits,
const u64 *private_key, const u64 *public_key,
u64 *secret);
+
+/**
+ * ecc_is_pubkey_valid_partial() - Partial public key validation
+ *
+ * @curve: elliptic curve domain parameters
+ * @pk: public key as a point
+ *
+ * Valdiate public key according to SP800-56A section 5.6.2.3.4 ECC Partial
+ * Public-Key Validation Routine.
+ *
+ * Note: There is no check that the public key is in the correct elliptic curve
+ * subgroup.
+ *
+ * Return: 0 if validation is successful, -EINVAL if validation is failed.
+ */
+int ecc_is_pubkey_valid_partial(const struct ecc_curve *curve,
+ struct ecc_point *pk);
+
+/**
+ * vli_is_zero() - Determine is vli is zero
+ *
+ * @vli: vli to check.
+ * @ndigits: length of the @vli
+ */
+bool vli_is_zero(const u64 *vli, unsigned int ndigits);
+
+/**
+ * vli_cmp() - compare left and right vlis
+ *
+ * @left: vli
+ * @right: vli
+ * @ndigits: length of both vlis
+ *
+ * Returns sign of @left - @right, i.e. -1 if @left < @right,
+ * 0 if @left == @right, 1 if @left > @right.
+ */
+int vli_cmp(const u64 *left, const u64 *right, unsigned int ndigits);
+
+/**
+ * vli_sub() - Subtracts right from left
+ *
+ * @result: where to write result
+ * @left: vli
+ * @right vli
+ * @ndigits: length of all vlis
+ *
+ * Note: can modify in-place.
+ *
+ * Return: carry bit.
+ */
+u64 vli_sub(u64 *result, const u64 *left, const u64 *right,
+ unsigned int ndigits);
+
+/**
+ * vli_mod_inv() - Modular inversion
+ *
+ * @result: where to write vli number
+ * @input: vli value to operate on
+ * @mod: modulus
+ * @ndigits: length of all vlis
+ */
+void vli_mod_inv(u64 *result, const u64 *input, const u64 *mod,
+ unsigned int ndigits);
+
#endif
diff --git a/crypto/ecc_curve_defs.h b/crypto/ecc_curve_defs.h
index 336ab1805639..69be6c7d228f 100644
--- a/crypto/ecc_curve_defs.h
+++ b/crypto/ecc_curve_defs.h
@@ -2,21 +2,6 @@
#ifndef _CRYTO_ECC_CURVE_DEFS_H
#define _CRYTO_ECC_CURVE_DEFS_H

-struct ecc_point {
- u64 *x;
- u64 *y;
- u8 ndigits;
-};
-
-struct ecc_curve {
- char *name;
- struct ecc_point g;
- u64 *p;
- u64 *n;
- u64 *a;
- u64 *b;
-};
-
/* NIST P-192: a = p - 3 */
static u64 nist_p192_g_x[] = { 0xF4FF0AFD82FF1012ull, 0x7CBF20EB43A18800ull,
0x188DA80EB03090F6ull };
--
2.11.0


2019-03-01 18:00:23

by Vitaly Chikunov

[permalink] [raw]
Subject: [PATCH v7 06/11] X.509: parse public key parameters from x509 for akcipher

Some public key algorithms (like EC-DSA) keep in parameters field
important data such as digest and curve OIDs (possibly more for
different EC-DSA variants). Thus, just setting a public key (as
for RSA) is not enough.

Append parameters into the key stream for akcipher_set_{pub,priv}_key.
Appended data is: (u32) algo OID, (u32) parameters length, parameters
data.

This does not affect current akcipher API nor RSA ciphers (they could
ignore it). Idea of appending parameters to the key stream is by Herbert
Xu.

Cc: David Howells <[email protected]>
Cc: [email protected]
Signed-off-by: Vitaly Chikunov <[email protected]>
---
crypto/asymmetric_keys/asym_tpm.c | 43 ++++++++++++++++--
crypto/asymmetric_keys/public_key.c | 72 ++++++++++++++++++++++++-------
crypto/asymmetric_keys/x509.asn1 | 2 +-
crypto/asymmetric_keys/x509_cert_parser.c | 31 +++++++++++++
crypto/testmgr.c | 24 +++++++++--
crypto/testmgr.h | 5 +++
include/crypto/akcipher.h | 18 ++++----
include/crypto/public_key.h | 4 ++
8 files changed, 168 insertions(+), 31 deletions(-)

diff --git a/crypto/asymmetric_keys/asym_tpm.c b/crypto/asymmetric_keys/asym_tpm.c
index 402fc34ca044..d95d7ec50e5a 100644
--- a/crypto/asymmetric_keys/asym_tpm.c
+++ b/crypto/asymmetric_keys/asym_tpm.c
@@ -395,6 +395,12 @@ static int determine_akcipher(const char *encoding, const char *hash_algo,
return -ENOPKG;
}

+static u8 *tpm_pack_u32(u8 *dst, u32 val)
+{
+ memcpy(dst, &val, sizeof(val));
+ return dst + sizeof(val);
+}
+
/*
* Query information about a key.
*/
@@ -407,6 +413,7 @@ static int tpm_key_query(const struct kernel_pkey_params *params,
struct crypto_akcipher *tfm;
uint8_t der_pub_key[PUB_KEY_BUF_SIZE];
uint32_t der_pub_key_len;
+ u8 *pkey, *ptr;
int len;

/* TPM only works on private keys, public keys still done in software */
@@ -421,7 +428,16 @@ static int tpm_key_query(const struct kernel_pkey_params *params,
der_pub_key_len = derive_pub_key(tk->pub_key, tk->pub_key_len,
der_pub_key);

- ret = crypto_akcipher_set_pub_key(tfm, der_pub_key, der_pub_key_len);
+ pkey = kmalloc(der_pub_key_len + sizeof(u32) * 2, GFP_KERNEL);
+ if (!pkey)
+ goto error_free_tfm;
+ memcpy(pkey, der_pub_key, der_pub_key_len);
+ ptr = pkey + der_pub_key_len;
+ /* Set dummy parameters to satisfy set_pub_key ABI. */
+ ptr = tpm_pack_u32(ptr, 0); /* algo */
+ ptr = tpm_pack_u32(ptr, 0); /* parameter length */
+
+ ret = crypto_akcipher_set_pub_key(tfm, pkey, der_pub_key_len);
if (ret < 0)
goto error_free_tfm;

@@ -440,6 +456,7 @@ static int tpm_key_query(const struct kernel_pkey_params *params,

ret = 0;
error_free_tfm:
+ kfree(pkey);
crypto_free_akcipher(tfm);
pr_devel("<==%s() = %d\n", __func__, ret);
return ret;
@@ -460,6 +477,7 @@ static int tpm_key_encrypt(struct tpm_key *tk,
struct scatterlist in_sg, out_sg;
uint8_t der_pub_key[PUB_KEY_BUF_SIZE];
uint32_t der_pub_key_len;
+ u8 *pkey, *ptr;
int ret;

pr_devel("==>%s()\n", __func__);
@@ -475,7 +493,15 @@ static int tpm_key_encrypt(struct tpm_key *tk,
der_pub_key_len = derive_pub_key(tk->pub_key, tk->pub_key_len,
der_pub_key);

- ret = crypto_akcipher_set_pub_key(tfm, der_pub_key, der_pub_key_len);
+ pkey = kmalloc(der_pub_key_len + sizeof(u32) * 2, GFP_KERNEL);
+ if (!pkey)
+ goto error_free_tfm;
+ memcpy(pkey, der_pub_key, der_pub_key_len);
+ ptr = pkey + der_pub_key_len;
+ ptr = tpm_pack_u32(ptr, 0); /* algo */
+ ptr = tpm_pack_u32(ptr, 0); /* parameter length */
+
+ ret = crypto_akcipher_set_pub_key(tfm, pkey, der_pub_key_len);
if (ret < 0)
goto error_free_tfm;

@@ -500,6 +526,7 @@ static int tpm_key_encrypt(struct tpm_key *tk,

akcipher_request_free(req);
error_free_tfm:
+ kfree(pkey);
crypto_free_akcipher(tfm);
pr_devel("<==%s() = %d\n", __func__, ret);
return ret;
@@ -748,6 +775,7 @@ static int tpm_key_verify_signature(const struct key *key,
char alg_name[CRYPTO_MAX_ALG_NAME];
uint8_t der_pub_key[PUB_KEY_BUF_SIZE];
uint32_t der_pub_key_len;
+ u8 *pkey, *ptr;
int ret;

pr_devel("==>%s()\n", __func__);
@@ -770,7 +798,15 @@ static int tpm_key_verify_signature(const struct key *key,
der_pub_key_len = derive_pub_key(tk->pub_key, tk->pub_key_len,
der_pub_key);

- ret = crypto_akcipher_set_pub_key(tfm, der_pub_key, der_pub_key_len);
+ pkey = kmalloc(der_pub_key_len + sizeof(u32) * 2, GFP_KERNEL);
+ if (!pkey)
+ goto error_free_tfm;
+ memcpy(pkey, der_pub_key, der_pub_key_len);
+ ptr = pkey + der_pub_key_len;
+ ptr = tpm_pack_u32(ptr, 0); /* algo */
+ ptr = tpm_pack_u32(ptr, 0); /* parameter length */
+
+ ret = crypto_akcipher_set_pub_key(tfm, pkey, der_pub_key_len);
if (ret < 0)
goto error_free_tfm;

@@ -792,6 +828,7 @@ static int tpm_key_verify_signature(const struct key *key,

akcipher_request_free(req);
error_free_tfm:
+ kfree(pkey);
crypto_free_akcipher(tfm);
pr_devel("<==%s() = %d\n", __func__, ret);
if (WARN_ON_ONCE(ret > 0))
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index 4dcfe281b898..0564951f8760 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -45,6 +45,7 @@ void public_key_free(struct public_key *key)
{
if (key) {
kfree(key->key);
+ kfree(key->params);
kfree(key);
}
}
@@ -94,6 +95,12 @@ int software_key_determine_akcipher(const char *encoding,
return -ENOPKG;
}

+static u8 *pkey_pack_u32(u8 *dst, u32 val)
+{
+ memcpy(dst, &val, sizeof(val));
+ return dst + sizeof(val);
+}
+
/*
* Query information about a key.
*/
@@ -103,6 +110,7 @@ static int software_key_query(const struct kernel_pkey_params *params,
struct crypto_akcipher *tfm;
struct public_key *pkey = params->key->payload.data[asym_crypto];
char alg_name[CRYPTO_MAX_ALG_NAME];
+ u8 *key, *ptr;
int ret, len;

ret = software_key_determine_akcipher(params->encoding,
@@ -115,14 +123,22 @@ static int software_key_query(const struct kernel_pkey_params *params,
if (IS_ERR(tfm))
return PTR_ERR(tfm);

+ key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
+ GFP_KERNEL);
+ if (!key)
+ goto error_free_tfm;
+ memcpy(key, pkey->key, pkey->keylen);
+ ptr = key + pkey->keylen;
+ ptr = pkey_pack_u32(ptr, pkey->algo);
+ ptr = pkey_pack_u32(ptr, pkey->paramlen);
+ memcpy(ptr, pkey->params, pkey->paramlen);
+
if (pkey->key_is_private)
- ret = crypto_akcipher_set_priv_key(tfm,
- pkey->key, pkey->keylen);
+ ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen);
else
- ret = crypto_akcipher_set_pub_key(tfm,
- pkey->key, pkey->keylen);
+ ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen);
if (ret < 0)
- goto error_free_tfm;
+ goto error_free_key;

len = crypto_akcipher_maxsize(tfm);
info->key_size = len * 8;
@@ -143,6 +159,8 @@ static int software_key_query(const struct kernel_pkey_params *params,
}
ret = 0;

+error_free_key:
+ kfree(key);
error_free_tfm:
crypto_free_akcipher(tfm);
pr_devel("<==%s() = %d\n", __func__, ret);
@@ -161,6 +179,7 @@ static int software_key_eds_op(struct kernel_pkey_params *params,
struct crypto_wait cwait;
struct scatterlist in_sg, out_sg;
char alg_name[CRYPTO_MAX_ALG_NAME];
+ char *key, *ptr;
int ret;

pr_devel("==>%s()\n", __func__);
@@ -179,14 +198,23 @@ static int software_key_eds_op(struct kernel_pkey_params *params,
if (!req)
goto error_free_tfm;

+ key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
+ GFP_KERNEL);
+ if (!key)
+ goto error_free_req;
+
+ memcpy(key, pkey->key, pkey->keylen);
+ ptr = key + pkey->keylen;
+ ptr = pkey_pack_u32(ptr, pkey->algo);
+ ptr = pkey_pack_u32(ptr, pkey->paramlen);
+ memcpy(ptr, pkey->params, pkey->paramlen);
+
if (pkey->key_is_private)
- ret = crypto_akcipher_set_priv_key(tfm,
- pkey->key, pkey->keylen);
+ ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen);
else
- ret = crypto_akcipher_set_pub_key(tfm,
- pkey->key, pkey->keylen);
+ ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen);
if (ret)
- goto error_free_req;
+ goto error_free_key;

sg_init_one(&in_sg, in, params->in_len);
sg_init_one(&out_sg, out, params->out_len);
@@ -216,6 +244,8 @@ static int software_key_eds_op(struct kernel_pkey_params *params,
if (ret == 0)
ret = req->dst_len;

+error_free_key:
+ kfree(key);
error_free_req:
akcipher_request_free(req);
error_free_tfm:
@@ -235,6 +265,7 @@ int public_key_verify_signature(const struct public_key *pkey,
struct akcipher_request *req;
struct scatterlist src_sg[2];
char alg_name[CRYPTO_MAX_ALG_NAME];
+ char *key, *ptr;
int ret;

pr_devel("==>%s()\n", __func__);
@@ -258,14 +289,23 @@ int public_key_verify_signature(const struct public_key *pkey,
if (!req)
goto error_free_tfm;

+ key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
+ GFP_KERNEL);
+ if (!key)
+ goto error_free_req;
+
+ memcpy(key, pkey->key, pkey->keylen);
+ ptr = key + pkey->keylen;
+ ptr = pkey_pack_u32(ptr, pkey->algo);
+ ptr = pkey_pack_u32(ptr, pkey->paramlen);
+ memcpy(ptr, pkey->params, pkey->paramlen);
+
if (pkey->key_is_private)
- ret = crypto_akcipher_set_priv_key(tfm,
- pkey->key, pkey->keylen);
+ ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen);
else
- ret = crypto_akcipher_set_pub_key(tfm,
- pkey->key, pkey->keylen);
+ ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen);
if (ret)
- goto error_free_req;
+ goto error_free_key;

sg_init_table(src_sg, 2);
sg_set_buf(&src_sg[0], sig->s, sig->s_size);
@@ -278,6 +318,8 @@ int public_key_verify_signature(const struct public_key *pkey,
crypto_req_done, &cwait);
ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait);

+error_free_key:
+ kfree(key);
error_free_req:
akcipher_request_free(req);
error_free_tfm:
diff --git a/crypto/asymmetric_keys/x509.asn1 b/crypto/asymmetric_keys/x509.asn1
index aae0cde414e2..5c9f4e4a5231 100644
--- a/crypto/asymmetric_keys/x509.asn1
+++ b/crypto/asymmetric_keys/x509.asn1
@@ -22,7 +22,7 @@ CertificateSerialNumber ::= INTEGER

AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER ({ x509_note_OID }),
- parameters ANY OPTIONAL
+ parameters ANY OPTIONAL ({ x509_note_params })
}

Name ::= SEQUENCE OF RelativeDistinguishedName
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
index 991f4d735a4e..b2cdf2db1987 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -26,6 +26,9 @@ struct x509_parse_context {
const void *cert_start; /* Start of cert content */
const void *key; /* Key data */
size_t key_size; /* Size of key data */
+ const void *params; /* Key parameters */
+ size_t params_size; /* Size of key parameters */
+ enum OID key_algo; /* Public key algorithm */
enum OID last_oid; /* Last OID encountered */
enum OID algo_oid; /* Algorithm OID */
unsigned char nr_mpi; /* Number of MPIs stored */
@@ -109,6 +112,13 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)

cert->pub->keylen = ctx->key_size;

+ cert->pub->params = kmemdup(ctx->params, ctx->params_size, GFP_KERNEL);
+ if (!cert->pub->params)
+ goto error_decode;
+
+ cert->pub->paramlen = ctx->params_size;
+ cert->pub->algo = ctx->key_algo;
+
/* Grab the signature bits */
ret = x509_get_sig_params(cert);
if (ret < 0)
@@ -401,6 +411,27 @@ int x509_note_subject(void *context, size_t hdrlen,
}

/*
+ * Extract the parameters for the public key
+ */
+int x509_note_params(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct x509_parse_context *ctx = context;
+
+ /*
+ * AlgorithmIdentifier is used three times in the x509, we should skip
+ * first and ignore third, using second one which is after subject and
+ * before subjectPublicKey.
+ */
+ if (!ctx->cert->raw_subject || ctx->key)
+ return 0;
+ ctx->params = value - hdrlen;
+ ctx->params_size = vlen + hdrlen;
+ return 0;
+}
+
+/*
* Extract the data for the public key algorithm
*/
int x509_extract_key_data(void *context, size_t hdrlen,
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 443d5b6f1045..50396b3a2a47 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -2493,6 +2493,12 @@ static int alg_test_kpp(const struct alg_test_desc *desc, const char *driver,
return err;
}

+static u8 *test_pack_u32(u8 *dst, u32 val)
+{
+ memcpy(dst, &val, sizeof(val));
+ return dst + sizeof(val);
+}
+
static int test_akcipher_one(struct crypto_akcipher *tfm,
const struct akcipher_testvec *vecs)
{
@@ -2507,6 +2513,7 @@ static int test_akcipher_one(struct crypto_akcipher *tfm,
const char *m, *c;
unsigned int m_size, c_size;
const char *op;
+ u8 *key, *ptr;

if (testmgr_alloc_buf(xbuf))
return err;
@@ -2517,12 +2524,20 @@ static int test_akcipher_one(struct crypto_akcipher *tfm,

crypto_init_wait(&wait);

+ key = kmalloc(vecs->key_len + sizeof(u32) * 2 + vecs->param_len,
+ GFP_KERNEL);
+ if (!key)
+ goto free_xbuf;
+ memcpy(key, vecs->key, vecs->key_len);
+ ptr = key + vecs->key_len;
+ ptr = test_pack_u32(ptr, vecs->algo);
+ ptr = test_pack_u32(ptr, vecs->param_len);
+ memcpy(ptr, vecs->params, vecs->param_len);
+
if (vecs->public_key_vec)
- err = crypto_akcipher_set_pub_key(tfm, vecs->key,
- vecs->key_len);
+ err = crypto_akcipher_set_pub_key(tfm, key, vecs->key_len);
else
- err = crypto_akcipher_set_priv_key(tfm, vecs->key,
- vecs->key_len);
+ err = crypto_akcipher_set_priv_key(tfm, key, vecs->key_len);
if (err)
goto free_req;

@@ -2652,6 +2667,7 @@ static int test_akcipher_one(struct crypto_akcipher *tfm,
kfree(outbuf_enc);
free_req:
akcipher_request_free(req);
+ kfree(key);
free_xbuf:
testmgr_free_buf(xbuf);
return err;
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index f267633cf13a..75d8f8c3e203 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -25,6 +25,8 @@
#ifndef _CRYPTO_TESTMGR_H
#define _CRYPTO_TESTMGR_H

+#include <linux/oid_registry.h>
+
#define MAX_IVLEN 32

/*
@@ -135,13 +137,16 @@ struct drbg_testvec {

struct akcipher_testvec {
const unsigned char *key;
+ const unsigned char *params;
const unsigned char *m;
const unsigned char *c;
unsigned int key_len;
+ unsigned int param_len;
unsigned int m_size;
unsigned int c_size;
bool public_key_vec;
bool siggen_sigver_test;
+ enum OID algo;
};

struct kpp_testvec {
diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
index 28ffa9ef03a9..4ecbedddd9a1 100644
--- a/include/crypto/akcipher.h
+++ b/include/crypto/akcipher.h
@@ -74,10 +74,10 @@ struct crypto_akcipher {
* operation
* @set_pub_key: Function invokes the algorithm specific set public key
* function, which knows how to decode and interpret
- * the BER encoded public key
+ * the BER encoded public key and parameters
* @set_priv_key: Function invokes the algorithm specific set private key
* function, which knows how to decode and interpret
- * the BER encoded private key
+ * the BER encoded private key and parameters
* @max_size: Function returns dest buffer size required for a given key.
* @init: Initialize the cryptographic transformation object.
* This function is used to initialize the cryptographic
@@ -388,11 +388,12 @@ static inline int crypto_akcipher_verify(struct akcipher_request *req)
* crypto_akcipher_set_pub_key() - Invoke set public key operation
*
* Function invokes the algorithm specific set key function, which knows
- * how to decode and interpret the encoded key
+ * how to decode and interpret the encoded key and parameters
*
* @tfm: tfm handle
- * @key: BER encoded public key
- * @keylen: length of the key
+ * @key: BER encoded public key, algo OID, paramlen, BER encoded
+ * parameters
+ * @keylen: length of the key (not including other data)
*
* Return: zero on success; error code in case of error
*/
@@ -409,11 +410,12 @@ static inline int crypto_akcipher_set_pub_key(struct crypto_akcipher *tfm,
* crypto_akcipher_set_priv_key() - Invoke set private key operation
*
* Function invokes the algorithm specific set key function, which knows
- * how to decode and interpret the encoded key
+ * how to decode and interpret the encoded keya and parameters
*
* @tfm: tfm handle
- * @key: BER encoded private key
- * @keylen: length of the key
+ * @key: BER encoded private key, algo OID, paramlen, BER encoded
+ * parameters
+ * @keylen: length of the key (not including other data)
*
* Return: zero on success; error code in case of error
*/
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index be626eac9113..712fe1214b5f 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -15,6 +15,7 @@
#define _LINUX_PUBLIC_KEY_H

#include <linux/keyctl.h>
+#include <linux/oid_registry.h>

/*
* Cryptographic data for the public-key subtype of the asymmetric key type.
@@ -25,6 +26,9 @@
struct public_key {
void *key;
u32 keylen;
+ enum OID algo;
+ void *params;
+ u32 paramlen;
bool key_is_private;
const char *id_type;
const char *pkey_algo;
--
2.11.0


2019-03-01 18:00:30

by Vitaly Chikunov

[permalink] [raw]
Subject: [PATCH v7 07/11] crypto: Kconfig - create Public-key cryptography section

Group RSA, DH, and ECDH into Public-key cryptography config section.

Signed-off-by: Vitaly Chikunov <[email protected]>
---
crypto/Kconfig | 48 +++++++++++++++++++++++++-----------------------
1 file changed, 25 insertions(+), 23 deletions(-)

diff --git a/crypto/Kconfig b/crypto/Kconfig
index bbab6bf33519..370cbdca87a7 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -113,29 +113,6 @@ config CRYPTO_ACOMP
select CRYPTO_ALGAPI
select CRYPTO_ACOMP2

-config CRYPTO_RSA
- tristate "RSA algorithm"
- select CRYPTO_AKCIPHER
- select CRYPTO_MANAGER
- select MPILIB
- select ASN1
- help
- Generic implementation of the RSA public key algorithm.
-
-config CRYPTO_DH
- tristate "Diffie-Hellman algorithm"
- select CRYPTO_KPP
- select MPILIB
- help
- Generic implementation of the Diffie-Hellman algorithm.
-
-config CRYPTO_ECDH
- tristate "ECDH algorithm"
- select CRYPTO_KPP
- select CRYPTO_RNG_DEFAULT
- help
- Generic implementation of the ECDH algorithm
-
config CRYPTO_MANAGER
tristate "Cryptographic algorithm manager"
select CRYPTO_MANAGER2
@@ -253,6 +230,31 @@ config CRYPTO_GLUE_HELPER_X86
config CRYPTO_ENGINE
tristate

+comment "Public-key cryptography"
+
+config CRYPTO_RSA
+ tristate "RSA algorithm"
+ select CRYPTO_AKCIPHER
+ select CRYPTO_MANAGER
+ select MPILIB
+ select ASN1
+ help
+ Generic implementation of the RSA public key algorithm.
+
+config CRYPTO_DH
+ tristate "Diffie-Hellman algorithm"
+ select CRYPTO_KPP
+ select MPILIB
+ help
+ Generic implementation of the Diffie-Hellman algorithm.
+
+config CRYPTO_ECDH
+ tristate "ECDH algorithm"
+ select CRYPTO_KPP
+ select CRYPTO_RNG_DEFAULT
+ help
+ Generic implementation of the ECDH algorithm
+
comment "Authenticated Encryption with Associated Data"

config CRYPTO_CCM
--
2.11.0


2019-03-01 18:00:31

by Vitaly Chikunov

[permalink] [raw]
Subject: [PATCH v7 05/11] KEYS: do not kmemdup digest in {public,tpm}_key_verify_signature

Treat (struct public_key_signature)'s digest same as its signature (s).
Since digest should be already in the kmalloc'd memory do not kmemdup
digest value before calling {public,tpm}_key_verify_signature.

Patch is split from the previous as suggested by Herbert Xu.

Suggested-by: David Howells <[email protected]>
Cc: David Howells <[email protected]>
Cc: [email protected]
Signed-off-by: Vitaly Chikunov <[email protected]>
---
crypto/asymmetric_keys/asym_tpm.c | 10 +---------
crypto/asymmetric_keys/public_key.c | 9 +--------
2 files changed, 2 insertions(+), 17 deletions(-)

diff --git a/crypto/asymmetric_keys/asym_tpm.c b/crypto/asymmetric_keys/asym_tpm.c
index 4e5b6fb57a94..402fc34ca044 100644
--- a/crypto/asymmetric_keys/asym_tpm.c
+++ b/crypto/asymmetric_keys/asym_tpm.c
@@ -748,7 +748,6 @@ static int tpm_key_verify_signature(const struct key *key,
char alg_name[CRYPTO_MAX_ALG_NAME];
uint8_t der_pub_key[PUB_KEY_BUF_SIZE];
uint32_t der_pub_key_len;
- void *digest;
int ret;

pr_devel("==>%s()\n", __func__);
@@ -780,14 +779,9 @@ static int tpm_key_verify_signature(const struct key *key,
if (!req)
goto error_free_tfm;

- ret = -ENOMEM;
- digest = kmemdup(sig->digest, sig->digest_size, GFP_KERNEL);
- if (!digest)
- goto error_free_req;
-
sg_init_table(src_sg, 2);
sg_set_buf(&src_sg[0], sig->s, sig->s_size);
- sg_set_buf(&src_sg[1], digest, sig->digest_size);
+ sg_set_buf(&src_sg[1], sig->digest, sig->digest_size);
akcipher_request_set_crypt(req, src_sg, NULL, sig->s_size,
sig->digest_size);
crypto_init_wait(&cwait);
@@ -796,8 +790,6 @@ static int tpm_key_verify_signature(const struct key *key,
crypto_req_done, &cwait);
ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait);

- kfree(digest);
-error_free_req:
akcipher_request_free(req);
error_free_tfm:
crypto_free_akcipher(tfm);
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index 338f2b5352b1..4dcfe281b898 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -235,7 +235,6 @@ int public_key_verify_signature(const struct public_key *pkey,
struct akcipher_request *req;
struct scatterlist src_sg[2];
char alg_name[CRYPTO_MAX_ALG_NAME];
- void *digest;
int ret;

pr_devel("==>%s()\n", __func__);
@@ -268,14 +267,9 @@ int public_key_verify_signature(const struct public_key *pkey,
if (ret)
goto error_free_req;

- ret = -ENOMEM;
- digest = kmemdup(sig->digest, sig->digest_size, GFP_KERNEL);
- if (!digest)
- goto error_free_req;
-
sg_init_table(src_sg, 2);
sg_set_buf(&src_sg[0], sig->s, sig->s_size);
- sg_set_buf(&src_sg[1], digest, sig->digest_size);
+ sg_set_buf(&src_sg[1], sig->digest, sig->digest_size);
akcipher_request_set_crypt(req, src_sg, NULL, sig->s_size,
sig->digest_size);
crypto_init_wait(&cwait);
@@ -284,7 +278,6 @@ int public_key_verify_signature(const struct public_key *pkey,
crypto_req_done, &cwait);
ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait);

- kfree(digest);
error_free_req:
akcipher_request_free(req);
error_free_tfm:
--
2.11.0


2019-03-01 18:00:32

by Vitaly Chikunov

[permalink] [raw]
Subject: [PATCH v7 03/11] crypto: rsa - unimplement sign/verify for raw RSA backends

In preparation for new akcipher verify call remove sign/verify callbacks
from RSA backends and make PKCS1 driver call encrypt/decrypt instead.

This also complies with the well-known idea that raw RSA should never be
used for sign/verify. It only should be used with proper padding scheme
such as PKCS1 driver provides.

Cc: Giovanni Cabiddu <[email protected]>
Cc: [email protected]
Cc: Tom Lendacky <[email protected]>
Cc: Gary Hook <[email protected]>
Cc: Horia Geantă <[email protected]>
Cc: Aymen Sghaier <[email protected]>
Signed-off-by: Vitaly Chikunov <[email protected]>
---
crypto/rsa-pkcs1pad.c | 4 +-
crypto/rsa.c | 109 --------------------------
drivers/crypto/caam/caampkc.c | 2 -
drivers/crypto/ccp/ccp-crypto-rsa.c | 2 -
drivers/crypto/qat/qat_common/qat_asym_algs.c | 2 -
5 files changed, 2 insertions(+), 117 deletions(-)

diff --git a/crypto/rsa-pkcs1pad.c b/crypto/rsa-pkcs1pad.c
index 0a6680ca8cb6..94382fa2c6ac 100644
--- a/crypto/rsa-pkcs1pad.c
+++ b/crypto/rsa-pkcs1pad.c
@@ -429,7 +429,7 @@ static int pkcs1pad_sign(struct akcipher_request *req)
akcipher_request_set_crypt(&req_ctx->child_req, req_ctx->in_sg,
req->dst, ctx->key_size - 1, req->dst_len);

- err = crypto_akcipher_sign(&req_ctx->child_req);
+ err = crypto_akcipher_decrypt(&req_ctx->child_req);
if (err != -EINPROGRESS && err != -EBUSY)
return pkcs1pad_encrypt_sign_complete(req, err);

@@ -551,7 +551,7 @@ static int pkcs1pad_verify(struct akcipher_request *req)
req_ctx->out_sg, req->src_len,
ctx->key_size);

- err = crypto_akcipher_verify(&req_ctx->child_req);
+ err = crypto_akcipher_encrypt(&req_ctx->child_req);
if (err != -EINPROGRESS && err != -EBUSY)
return pkcs1pad_verify_complete(req, err);

diff --git a/crypto/rsa.c b/crypto/rsa.c
index 4167980c243d..5d427c1100d6 100644
--- a/crypto/rsa.c
+++ b/crypto/rsa.c
@@ -50,34 +50,6 @@ static int _rsa_dec(const struct rsa_mpi_key *key, MPI m, MPI c)
return mpi_powm(m, c, key->d, key->n);
}

-/*
- * RSASP1 function [RFC3447 sec 5.2.1]
- * s = m^d mod n
- */
-static int _rsa_sign(const struct rsa_mpi_key *key, MPI s, MPI m)
-{
- /* (1) Validate 0 <= m < n */
- if (mpi_cmp_ui(m, 0) < 0 || mpi_cmp(m, key->n) >= 0)
- return -EINVAL;
-
- /* (2) s = m^d mod n */
- return mpi_powm(s, m, key->d, key->n);
-}
-
-/*
- * RSAVP1 function [RFC3447 sec 5.2.2]
- * m = s^e mod n;
- */
-static int _rsa_verify(const struct rsa_mpi_key *key, MPI m, MPI s)
-{
- /* (1) Validate 0 <= s < n */
- if (mpi_cmp_ui(s, 0) < 0 || mpi_cmp(s, key->n) >= 0)
- return -EINVAL;
-
- /* (2) m = s^e mod n */
- return mpi_powm(m, s, key->e, key->n);
-}
-
static inline struct rsa_mpi_key *rsa_get_key(struct crypto_akcipher *tfm)
{
return akcipher_tfm_ctx(tfm);
@@ -160,85 +132,6 @@ static int rsa_dec(struct akcipher_request *req)
return ret;
}

-static int rsa_sign(struct akcipher_request *req)
-{
- struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
- const struct rsa_mpi_key *pkey = rsa_get_key(tfm);
- MPI m, s = mpi_alloc(0);
- int ret = 0;
- int sign;
-
- if (!s)
- return -ENOMEM;
-
- if (unlikely(!pkey->n || !pkey->d)) {
- ret = -EINVAL;
- goto err_free_s;
- }
-
- ret = -ENOMEM;
- m = mpi_read_raw_from_sgl(req->src, req->src_len);
- if (!m)
- goto err_free_s;
-
- ret = _rsa_sign(pkey, s, m);
- if (ret)
- goto err_free_m;
-
- ret = mpi_write_to_sgl(s, req->dst, req->dst_len, &sign);
- if (ret)
- goto err_free_m;
-
- if (sign < 0)
- ret = -EBADMSG;
-
-err_free_m:
- mpi_free(m);
-err_free_s:
- mpi_free(s);
- return ret;
-}
-
-static int rsa_verify(struct akcipher_request *req)
-{
- struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
- const struct rsa_mpi_key *pkey = rsa_get_key(tfm);
- MPI s, m = mpi_alloc(0);
- int ret = 0;
- int sign;
-
- if (!m)
- return -ENOMEM;
-
- if (unlikely(!pkey->n || !pkey->e)) {
- ret = -EINVAL;
- goto err_free_m;
- }
-
- s = mpi_read_raw_from_sgl(req->src, req->src_len);
- if (!s) {
- ret = -ENOMEM;
- goto err_free_m;
- }
-
- ret = _rsa_verify(pkey, m, s);
- if (ret)
- goto err_free_s;
-
- ret = mpi_write_to_sgl(m, req->dst, req->dst_len, &sign);
- if (ret)
- goto err_free_s;
-
- if (sign < 0)
- ret = -EBADMSG;
-
-err_free_s:
- mpi_free(s);
-err_free_m:
- mpi_free(m);
- return ret;
-}
-
static void rsa_free_mpi_key(struct rsa_mpi_key *key)
{
mpi_free(key->d);
@@ -353,8 +246,6 @@ static void rsa_exit_tfm(struct crypto_akcipher *tfm)
static struct akcipher_alg rsa = {
.encrypt = rsa_enc,
.decrypt = rsa_dec,
- .sign = rsa_sign,
- .verify = rsa_verify,
.set_priv_key = rsa_set_priv_key,
.set_pub_key = rsa_set_pub_key,
.max_size = rsa_max_size,
diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c
index 77ab28a2811a..d7e1fc5bacc5 100644
--- a/drivers/crypto/caam/caampkc.c
+++ b/drivers/crypto/caam/caampkc.c
@@ -994,8 +994,6 @@ static void caam_rsa_exit_tfm(struct crypto_akcipher *tfm)
static struct akcipher_alg caam_rsa = {
.encrypt = caam_rsa_enc,
.decrypt = caam_rsa_dec,
- .sign = caam_rsa_dec,
- .verify = caam_rsa_enc,
.set_pub_key = caam_rsa_set_pub_key,
.set_priv_key = caam_rsa_set_priv_key,
.max_size = caam_rsa_max_size,
diff --git a/drivers/crypto/ccp/ccp-crypto-rsa.c b/drivers/crypto/ccp/ccp-crypto-rsa.c
index 05850dfd7940..71e40680c880 100644
--- a/drivers/crypto/ccp/ccp-crypto-rsa.c
+++ b/drivers/crypto/ccp/ccp-crypto-rsa.c
@@ -214,8 +214,6 @@ static void ccp_rsa_exit_tfm(struct crypto_akcipher *tfm)
static struct akcipher_alg ccp_rsa_defaults = {
.encrypt = ccp_rsa_encrypt,
.decrypt = ccp_rsa_decrypt,
- .sign = ccp_rsa_decrypt,
- .verify = ccp_rsa_encrypt,
.set_pub_key = ccp_rsa_setpubkey,
.set_priv_key = ccp_rsa_setprivkey,
.max_size = ccp_rsa_maxsize,
diff --git a/drivers/crypto/qat/qat_common/qat_asym_algs.c b/drivers/crypto/qat/qat_common/qat_asym_algs.c
index 320e7854b4ee..c05d03565e96 100644
--- a/drivers/crypto/qat/qat_common/qat_asym_algs.c
+++ b/drivers/crypto/qat/qat_common/qat_asym_algs.c
@@ -1300,8 +1300,6 @@ static void qat_rsa_exit_tfm(struct crypto_akcipher *tfm)
static struct akcipher_alg rsa = {
.encrypt = qat_rsa_enc,
.decrypt = qat_rsa_dec,
- .sign = qat_rsa_dec,
- .verify = qat_rsa_enc,
.set_pub_key = qat_rsa_setpubkey,
.set_priv_key = qat_rsa_setprivkey,
.max_size = qat_rsa_max_size,
--
2.11.0


2019-03-01 18:00:39

by Vitaly Chikunov

[permalink] [raw]
Subject: [PATCH v7 02/11] crypto: akcipher - check the presence of callback before the call

Because with introduction of EC-RDSA and change in workings of RSA in
regard to sign/verify, akcipher could have not all callbacks defined,
check the presence of callbacks before calling them to increase
robustness.

Signed-off-by: Vitaly Chikunov <[email protected]>
---
include/crypto/akcipher.h | 25 ++++++++++++++++---------
1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
index 2d690494568c..f537fad1989f 100644
--- a/include/crypto/akcipher.h
+++ b/include/crypto/akcipher.h
@@ -268,7 +268,10 @@ static inline unsigned int crypto_akcipher_maxsize(struct crypto_akcipher *tfm)
{
struct akcipher_alg *alg = crypto_akcipher_alg(tfm);

- return alg->max_size(tfm);
+ if (alg->max_size)
+ return alg->max_size(tfm);
+ else
+ return 0;
}

/**
@@ -287,10 +290,11 @@ static inline int crypto_akcipher_encrypt(struct akcipher_request *req)
struct akcipher_alg *alg = crypto_akcipher_alg(tfm);
struct crypto_alg *calg = tfm->base.__crt_alg;
unsigned int src_len = req->src_len;
- int ret;
+ int ret = -ENOSYS;

crypto_stats_get(calg);
- ret = alg->encrypt(req);
+ if (alg->encrypt)
+ ret = alg->encrypt(req);
crypto_stats_akcipher_encrypt(src_len, ret, calg);
return ret;
}
@@ -311,10 +315,11 @@ static inline int crypto_akcipher_decrypt(struct akcipher_request *req)
struct akcipher_alg *alg = crypto_akcipher_alg(tfm);
struct crypto_alg *calg = tfm->base.__crt_alg;
unsigned int src_len = req->src_len;
- int ret;
+ int ret = -ENOSYS;

crypto_stats_get(calg);
- ret = alg->decrypt(req);
+ if (alg->decrypt)
+ ret = alg->decrypt(req);
crypto_stats_akcipher_decrypt(src_len, ret, calg);
return ret;
}
@@ -334,10 +339,11 @@ static inline int crypto_akcipher_sign(struct akcipher_request *req)
struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
struct akcipher_alg *alg = crypto_akcipher_alg(tfm);
struct crypto_alg *calg = tfm->base.__crt_alg;
- int ret;
+ int ret = -ENOSYS;

crypto_stats_get(calg);
- ret = alg->sign(req);
+ if (alg->sign)
+ ret = alg->sign(req);
crypto_stats_akcipher_sign(ret, calg);
return ret;
}
@@ -357,10 +363,11 @@ static inline int crypto_akcipher_verify(struct akcipher_request *req)
struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
struct akcipher_alg *alg = crypto_akcipher_alg(tfm);
struct crypto_alg *calg = tfm->base.__crt_alg;
- int ret;
+ int ret = -ENOSYS;

crypto_stats_get(calg);
- ret = alg->verify(req);
+ if (alg->verify)
+ ret = alg->verify(req);
crypto_stats_akcipher_verify(ret, calg);
return ret;
}
--
2.11.0


2019-03-21 11:19:33

by Herbert Xu

[permalink] [raw]
Subject: Re: [PATCH v7 02/11] crypto: akcipher - check the presence of callback before the call

On Fri, Mar 01, 2019 at 08:59:09PM +0300, Vitaly Chikunov wrote:
> Because with introduction of EC-RDSA and change in workings of RSA in
> regard to sign/verify, akcipher could have not all callbacks defined,
> check the presence of callbacks before calling them to increase
> robustness.
>
> Signed-off-by: Vitaly Chikunov <[email protected]>
> ---
> include/crypto/akcipher.h | 25 ++++++++++++++++---------
> 1 file changed, 16 insertions(+), 9 deletions(-)
>
> diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
> index 2d690494568c..f537fad1989f 100644
> --- a/include/crypto/akcipher.h
> +++ b/include/crypto/akcipher.h
> @@ -268,7 +268,10 @@ static inline unsigned int crypto_akcipher_maxsize(struct crypto_akcipher *tfm)
> {
> struct akcipher_alg *alg = crypto_akcipher_alg(tfm);
>
> - return alg->max_size(tfm);
> + if (alg->max_size)
> + return alg->max_size(tfm);
> + else
> + return 0;
> }

Please do these checks at registration time instead and provide
default implementations as needed.

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

2019-03-21 11:42:21

by Vitaly Chikunov

[permalink] [raw]
Subject: Re: [PATCH v7 02/11] crypto: akcipher - check the presence of callback before the call

Herbert,

On Thu, Mar 21, 2019 at 07:19:18PM +0800, Herbert Xu wrote:
> On Fri, Mar 01, 2019 at 08:59:09PM +0300, Vitaly Chikunov wrote:
> > Because with introduction of EC-RDSA and change in workings of RSA in
> > regard to sign/verify, akcipher could have not all callbacks defined,
> > check the presence of callbacks before calling them to increase
> > robustness.
> >
> > Signed-off-by: Vitaly Chikunov <[email protected]>
> > ---
> > include/crypto/akcipher.h | 25 ++++++++++++++++---------
> > 1 file changed, 16 insertions(+), 9 deletions(-)
> >
> > diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
> > index 2d690494568c..f537fad1989f 100644
> > --- a/include/crypto/akcipher.h
> > +++ b/include/crypto/akcipher.h
> > @@ -268,7 +268,10 @@ static inline unsigned int crypto_akcipher_maxsize(struct crypto_akcipher *tfm)
> > {
> > struct akcipher_alg *alg = crypto_akcipher_alg(tfm);
> >
> > - return alg->max_size(tfm);
> > + if (alg->max_size)
> > + return alg->max_size(tfm);
> > + else
> > + return 0;
> > }
>
> Please do these checks at registration time instead and provide
> default implementations as needed.

I guess patch "PATCH v7 01/11] KEYS: report to keyctl only actually
supported key ops" should also be removed and will infer anything from
presence of the callbacks.


Thanks,


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

2019-03-21 12:11:44

by Herbert Xu

[permalink] [raw]
Subject: Re: [PATCH v7 02/11] crypto: akcipher - check the presence of callback before the call

On Thu, Mar 21, 2019 at 02:42:10PM +0300, Vitaly Chikunov wrote:
>
> I guess patch "PATCH v7 01/11] KEYS: report to keyctl only actually
> supported key ops" should also be removed and will infer anything from
> presence of the callbacks.

Indeed. Especially if this is exposed to user-space then you
need to be careful changing the user-space API by clearing the
verify/sign bits for raw RSA.

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

2019-03-22 12:40:18

by Herbert Xu

[permalink] [raw]
Subject: Re: [PATCH v7 00/11] crypto: add EC-RDSA (GOST 34.10) algorithm

On Fri, Mar 01, 2019 at 08:59:07PM +0300, Vitaly Chikunov wrote:
> This patchset changes akcipher API to support ECDSA style signature
> verification, augments x509 parser to make it work with EC-RDSA certificates,
> and, finally, implements EC-RDSA (GOST 34.10) signature verification and its
> integration with IMA.
>
> This patchset should be applied over cryptodev commit 0918f18c7179e8cdf718d0.

I don't have any major issues with this patch-set (apart from the
minor issue with the crypto API).

However, as a number of patches are against areas outside of the
crypto API I would need to get acks for those patches from the
relevant maintainers.

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

2019-03-22 19:15:06

by Vitaly Chikunov

[permalink] [raw]
Subject: Re: [PATCH v7 11/11] integrity: support EC-RDSA signatures for asymmetric_verify

Mimi, Dmitry,

Can you Ack this patch?

Thanks,

On Fri, Mar 01, 2019 at 08:59:18PM +0300, Vitaly Chikunov wrote:
> Allow to use EC-RDSA signatures for IMA by determining signature type by
> the hash algorithm name. This works good for EC-RDSA since Streebog and
> EC-RDSA should always be used together.
>
> Cc: Mimi Zohar <[email protected]>
> Cc: Dmitry Kasatkin <[email protected]>
> Cc: [email protected]
> Signed-off-by: Vitaly Chikunov <[email protected]>
> ---
> security/integrity/digsig_asymmetric.c | 11 +++++++++--
> 1 file changed, 9 insertions(+), 2 deletions(-)
>
> diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
> index d775e03fbbcc..99080871eb9f 100644
> --- a/security/integrity/digsig_asymmetric.c
> +++ b/security/integrity/digsig_asymmetric.c
> @@ -104,9 +104,16 @@ int asymmetric_verify(struct key *keyring, const char *sig,
>
> memset(&pks, 0, sizeof(pks));
>
> - pks.pkey_algo = "rsa";
> pks.hash_algo = hash_algo_name[hdr->hash_algo];
> - pks.encoding = "pkcs1";
> + if (hdr->hash_algo == HASH_ALGO_STREEBOG_256 ||
> + hdr->hash_algo == HASH_ALGO_STREEBOG_512) {
> + /* EC-RDSA and Streebog should go together. */
> + pks.pkey_algo = "ecrdsa";
> + pks.encoding = "raw";
> + } else {
> + pks.pkey_algo = "rsa";
> + pks.encoding = "pkcs1";
> + }
> pks.digest = (u8 *)data;
> pks.digest_size = datalen;
> pks.s = hdr->sig;
> --
> 2.11.0

2019-03-22 19:21:57

by Vitaly Chikunov

[permalink] [raw]
Subject: Re: [PATCH v7 03/11] crypto: rsa - unimplement sign/verify for raw RSA backends

Giovanni Cabiddu,

Can you Ack this patch as it includes small change to QAT driver.

Tom Lendacky, Gary Hook,

Can you Ack this patch as it includes small change to CCP driver.

Horia Geantă, Aymen Sghaier,

Can you Ack this patch as it includes small change to CAAM driver.

Thanks,

On Fri, Mar 01, 2019 at 08:59:10PM +0300, Vitaly Chikunov wrote:
> In preparation for new akcipher verify call remove sign/verify callbacks
> from RSA backends and make PKCS1 driver call encrypt/decrypt instead.
>
> This also complies with the well-known idea that raw RSA should never be
> used for sign/verify. It only should be used with proper padding scheme
> such as PKCS1 driver provides.
>
> Cc: Giovanni Cabiddu <[email protected]>
> Cc: [email protected]
> Cc: Tom Lendacky <[email protected]>
> Cc: Gary Hook <[email protected]>
> Cc: Horia Geantă <[email protected]>
> Cc: Aymen Sghaier <[email protected]>
> Signed-off-by: Vitaly Chikunov <[email protected]>
> ---
> crypto/rsa-pkcs1pad.c | 4 +-
> crypto/rsa.c | 109 --------------------------
> drivers/crypto/caam/caampkc.c | 2 -
> drivers/crypto/ccp/ccp-crypto-rsa.c | 2 -
> drivers/crypto/qat/qat_common/qat_asym_algs.c | 2 -
> 5 files changed, 2 insertions(+), 117 deletions(-)
>
> diff --git a/crypto/rsa-pkcs1pad.c b/crypto/rsa-pkcs1pad.c
> index 0a6680ca8cb6..94382fa2c6ac 100644
> --- a/crypto/rsa-pkcs1pad.c
> +++ b/crypto/rsa-pkcs1pad.c
> @@ -429,7 +429,7 @@ static int pkcs1pad_sign(struct akcipher_request *req)
> akcipher_request_set_crypt(&req_ctx->child_req, req_ctx->in_sg,
> req->dst, ctx->key_size - 1, req->dst_len);
>
> - err = crypto_akcipher_sign(&req_ctx->child_req);
> + err = crypto_akcipher_decrypt(&req_ctx->child_req);
> if (err != -EINPROGRESS && err != -EBUSY)
> return pkcs1pad_encrypt_sign_complete(req, err);
>
> @@ -551,7 +551,7 @@ static int pkcs1pad_verify(struct akcipher_request *req)
> req_ctx->out_sg, req->src_len,
> ctx->key_size);
>
> - err = crypto_akcipher_verify(&req_ctx->child_req);
> + err = crypto_akcipher_encrypt(&req_ctx->child_req);
> if (err != -EINPROGRESS && err != -EBUSY)
> return pkcs1pad_verify_complete(req, err);
>
> diff --git a/crypto/rsa.c b/crypto/rsa.c
> index 4167980c243d..5d427c1100d6 100644
> --- a/crypto/rsa.c
> +++ b/crypto/rsa.c
> @@ -50,34 +50,6 @@ static int _rsa_dec(const struct rsa_mpi_key *key, MPI m, MPI c)
> return mpi_powm(m, c, key->d, key->n);
> }
>
> -/*
> - * RSASP1 function [RFC3447 sec 5.2.1]
> - * s = m^d mod n
> - */
> -static int _rsa_sign(const struct rsa_mpi_key *key, MPI s, MPI m)
> -{
> - /* (1) Validate 0 <= m < n */
> - if (mpi_cmp_ui(m, 0) < 0 || mpi_cmp(m, key->n) >= 0)
> - return -EINVAL;
> -
> - /* (2) s = m^d mod n */
> - return mpi_powm(s, m, key->d, key->n);
> -}
> -
> -/*
> - * RSAVP1 function [RFC3447 sec 5.2.2]
> - * m = s^e mod n;
> - */
> -static int _rsa_verify(const struct rsa_mpi_key *key, MPI m, MPI s)
> -{
> - /* (1) Validate 0 <= s < n */
> - if (mpi_cmp_ui(s, 0) < 0 || mpi_cmp(s, key->n) >= 0)
> - return -EINVAL;
> -
> - /* (2) m = s^e mod n */
> - return mpi_powm(m, s, key->e, key->n);
> -}
> -
> static inline struct rsa_mpi_key *rsa_get_key(struct crypto_akcipher *tfm)
> {
> return akcipher_tfm_ctx(tfm);
> @@ -160,85 +132,6 @@ static int rsa_dec(struct akcipher_request *req)
> return ret;
> }
>
> -static int rsa_sign(struct akcipher_request *req)
> -{
> - struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
> - const struct rsa_mpi_key *pkey = rsa_get_key(tfm);
> - MPI m, s = mpi_alloc(0);
> - int ret = 0;
> - int sign;
> -
> - if (!s)
> - return -ENOMEM;
> -
> - if (unlikely(!pkey->n || !pkey->d)) {
> - ret = -EINVAL;
> - goto err_free_s;
> - }
> -
> - ret = -ENOMEM;
> - m = mpi_read_raw_from_sgl(req->src, req->src_len);
> - if (!m)
> - goto err_free_s;
> -
> - ret = _rsa_sign(pkey, s, m);
> - if (ret)
> - goto err_free_m;
> -
> - ret = mpi_write_to_sgl(s, req->dst, req->dst_len, &sign);
> - if (ret)
> - goto err_free_m;
> -
> - if (sign < 0)
> - ret = -EBADMSG;
> -
> -err_free_m:
> - mpi_free(m);
> -err_free_s:
> - mpi_free(s);
> - return ret;
> -}
> -
> -static int rsa_verify(struct akcipher_request *req)
> -{
> - struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
> - const struct rsa_mpi_key *pkey = rsa_get_key(tfm);
> - MPI s, m = mpi_alloc(0);
> - int ret = 0;
> - int sign;
> -
> - if (!m)
> - return -ENOMEM;
> -
> - if (unlikely(!pkey->n || !pkey->e)) {
> - ret = -EINVAL;
> - goto err_free_m;
> - }
> -
> - s = mpi_read_raw_from_sgl(req->src, req->src_len);
> - if (!s) {
> - ret = -ENOMEM;
> - goto err_free_m;
> - }
> -
> - ret = _rsa_verify(pkey, m, s);
> - if (ret)
> - goto err_free_s;
> -
> - ret = mpi_write_to_sgl(m, req->dst, req->dst_len, &sign);
> - if (ret)
> - goto err_free_s;
> -
> - if (sign < 0)
> - ret = -EBADMSG;
> -
> -err_free_s:
> - mpi_free(s);
> -err_free_m:
> - mpi_free(m);
> - return ret;
> -}
> -
> static void rsa_free_mpi_key(struct rsa_mpi_key *key)
> {
> mpi_free(key->d);
> @@ -353,8 +246,6 @@ static void rsa_exit_tfm(struct crypto_akcipher *tfm)
> static struct akcipher_alg rsa = {
> .encrypt = rsa_enc,
> .decrypt = rsa_dec,
> - .sign = rsa_sign,
> - .verify = rsa_verify,
> .set_priv_key = rsa_set_priv_key,
> .set_pub_key = rsa_set_pub_key,
> .max_size = rsa_max_size,
> diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c
> index 77ab28a2811a..d7e1fc5bacc5 100644
> --- a/drivers/crypto/caam/caampkc.c
> +++ b/drivers/crypto/caam/caampkc.c
> @@ -994,8 +994,6 @@ static void caam_rsa_exit_tfm(struct crypto_akcipher *tfm)
> static struct akcipher_alg caam_rsa = {
> .encrypt = caam_rsa_enc,
> .decrypt = caam_rsa_dec,
> - .sign = caam_rsa_dec,
> - .verify = caam_rsa_enc,
> .set_pub_key = caam_rsa_set_pub_key,
> .set_priv_key = caam_rsa_set_priv_key,
> .max_size = caam_rsa_max_size,
> diff --git a/drivers/crypto/ccp/ccp-crypto-rsa.c b/drivers/crypto/ccp/ccp-crypto-rsa.c
> index 05850dfd7940..71e40680c880 100644
> --- a/drivers/crypto/ccp/ccp-crypto-rsa.c
> +++ b/drivers/crypto/ccp/ccp-crypto-rsa.c
> @@ -214,8 +214,6 @@ static void ccp_rsa_exit_tfm(struct crypto_akcipher *tfm)
> static struct akcipher_alg ccp_rsa_defaults = {
> .encrypt = ccp_rsa_encrypt,
> .decrypt = ccp_rsa_decrypt,
> - .sign = ccp_rsa_decrypt,
> - .verify = ccp_rsa_encrypt,
> .set_pub_key = ccp_rsa_setpubkey,
> .set_priv_key = ccp_rsa_setprivkey,
> .max_size = ccp_rsa_maxsize,
> diff --git a/drivers/crypto/qat/qat_common/qat_asym_algs.c b/drivers/crypto/qat/qat_common/qat_asym_algs.c
> index 320e7854b4ee..c05d03565e96 100644
> --- a/drivers/crypto/qat/qat_common/qat_asym_algs.c
> +++ b/drivers/crypto/qat/qat_common/qat_asym_algs.c
> @@ -1300,8 +1300,6 @@ static void qat_rsa_exit_tfm(struct crypto_akcipher *tfm)
> static struct akcipher_alg rsa = {
> .encrypt = qat_rsa_enc,
> .decrypt = qat_rsa_dec,
> - .sign = qat_rsa_dec,
> - .verify = qat_rsa_enc,
> .set_pub_key = qat_rsa_setpubkey,
> .set_priv_key = qat_rsa_setprivkey,
> .max_size = qat_rsa_max_size,
> --
> 2.11.0

2019-03-22 19:49:36

by Vitaly Chikunov

[permalink] [raw]
Subject: Re: [PATCH v7 05/11] KEYS: do not kmemdup digest in {public,tpm}_key_verify_signature

David,

Can you please Ack this patch, it changes ASYMMETRIC KEYS tree, and
incorporates modifications you requested before.

Thanks,

On Fri, Mar 01, 2019 at 08:59:12PM +0300, Vitaly Chikunov wrote:
> Treat (struct public_key_signature)'s digest same as its signature (s).
> Since digest should be already in the kmalloc'd memory do not kmemdup
> digest value before calling {public,tpm}_key_verify_signature.
>
> Patch is split from the previous as suggested by Herbert Xu.
>
> Suggested-by: David Howells <[email protected]>
> Cc: David Howells <[email protected]>
> Cc: [email protected]
> Signed-off-by: Vitaly Chikunov <[email protected]>
> ---
> crypto/asymmetric_keys/asym_tpm.c | 10 +---------
> crypto/asymmetric_keys/public_key.c | 9 +--------
> 2 files changed, 2 insertions(+), 17 deletions(-)
>
> diff --git a/crypto/asymmetric_keys/asym_tpm.c b/crypto/asymmetric_keys/asym_tpm.c
> index 4e5b6fb57a94..402fc34ca044 100644
> --- a/crypto/asymmetric_keys/asym_tpm.c
> +++ b/crypto/asymmetric_keys/asym_tpm.c
> @@ -748,7 +748,6 @@ static int tpm_key_verify_signature(const struct key *key,
> char alg_name[CRYPTO_MAX_ALG_NAME];
> uint8_t der_pub_key[PUB_KEY_BUF_SIZE];
> uint32_t der_pub_key_len;
> - void *digest;
> int ret;
>
> pr_devel("==>%s()\n", __func__);
> @@ -780,14 +779,9 @@ static int tpm_key_verify_signature(const struct key *key,
> if (!req)
> goto error_free_tfm;
>
> - ret = -ENOMEM;
> - digest = kmemdup(sig->digest, sig->digest_size, GFP_KERNEL);
> - if (!digest)
> - goto error_free_req;
> -
> sg_init_table(src_sg, 2);
> sg_set_buf(&src_sg[0], sig->s, sig->s_size);
> - sg_set_buf(&src_sg[1], digest, sig->digest_size);
> + sg_set_buf(&src_sg[1], sig->digest, sig->digest_size);
> akcipher_request_set_crypt(req, src_sg, NULL, sig->s_size,
> sig->digest_size);
> crypto_init_wait(&cwait);
> @@ -796,8 +790,6 @@ static int tpm_key_verify_signature(const struct key *key,
> crypto_req_done, &cwait);
> ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait);
>
> - kfree(digest);
> -error_free_req:
> akcipher_request_free(req);
> error_free_tfm:
> crypto_free_akcipher(tfm);
> diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
> index 338f2b5352b1..4dcfe281b898 100644
> --- a/crypto/asymmetric_keys/public_key.c
> +++ b/crypto/asymmetric_keys/public_key.c
> @@ -235,7 +235,6 @@ int public_key_verify_signature(const struct public_key *pkey,
> struct akcipher_request *req;
> struct scatterlist src_sg[2];
> char alg_name[CRYPTO_MAX_ALG_NAME];
> - void *digest;
> int ret;
>
> pr_devel("==>%s()\n", __func__);
> @@ -268,14 +267,9 @@ int public_key_verify_signature(const struct public_key *pkey,
> if (ret)
> goto error_free_req;
>
> - ret = -ENOMEM;
> - digest = kmemdup(sig->digest, sig->digest_size, GFP_KERNEL);
> - if (!digest)
> - goto error_free_req;
> -
> sg_init_table(src_sg, 2);
> sg_set_buf(&src_sg[0], sig->s, sig->s_size);
> - sg_set_buf(&src_sg[1], digest, sig->digest_size);
> + sg_set_buf(&src_sg[1], sig->digest, sig->digest_size);
> akcipher_request_set_crypt(req, src_sg, NULL, sig->s_size,
> sig->digest_size);
> crypto_init_wait(&cwait);
> @@ -284,7 +278,6 @@ int public_key_verify_signature(const struct public_key *pkey,
> crypto_req_done, &cwait);
> ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait);
>
> - kfree(digest);
> error_free_req:
> akcipher_request_free(req);
> error_free_tfm:
> --
> 2.11.0

2019-03-22 19:50:20

by Vitaly Chikunov

[permalink] [raw]
Subject: Re: [PATCH v7 06/11] X.509: parse public key parameters from x509 for akcipher

David,

Can you please Ack this patch or suggest modifications as it includes
changes to ASYMMETRIC KEYS tree?

Thanks,

On Fri, Mar 01, 2019 at 08:59:13PM +0300, Vitaly Chikunov wrote:
> Some public key algorithms (like EC-DSA) keep in parameters field
> important data such as digest and curve OIDs (possibly more for
> different EC-DSA variants). Thus, just setting a public key (as
> for RSA) is not enough.
>
> Append parameters into the key stream for akcipher_set_{pub,priv}_key.
> Appended data is: (u32) algo OID, (u32) parameters length, parameters
> data.
>
> This does not affect current akcipher API nor RSA ciphers (they could
> ignore it). Idea of appending parameters to the key stream is by Herbert
> Xu.
>
> Cc: David Howells <[email protected]>
> Cc: [email protected]
> Signed-off-by: Vitaly Chikunov <[email protected]>
> ---
> crypto/asymmetric_keys/asym_tpm.c | 43 ++++++++++++++++--
> crypto/asymmetric_keys/public_key.c | 72 ++++++++++++++++++++++++-------
> crypto/asymmetric_keys/x509.asn1 | 2 +-
> crypto/asymmetric_keys/x509_cert_parser.c | 31 +++++++++++++
> crypto/testmgr.c | 24 +++++++++--
> crypto/testmgr.h | 5 +++
> include/crypto/akcipher.h | 18 ++++----
> include/crypto/public_key.h | 4 ++
> 8 files changed, 168 insertions(+), 31 deletions(-)
>
> diff --git a/crypto/asymmetric_keys/asym_tpm.c b/crypto/asymmetric_keys/asym_tpm.c
> index 402fc34ca044..d95d7ec50e5a 100644
> --- a/crypto/asymmetric_keys/asym_tpm.c
> +++ b/crypto/asymmetric_keys/asym_tpm.c
> @@ -395,6 +395,12 @@ static int determine_akcipher(const char *encoding, const char *hash_algo,
> return -ENOPKG;
> }
>
> +static u8 *tpm_pack_u32(u8 *dst, u32 val)
> +{
> + memcpy(dst, &val, sizeof(val));
> + return dst + sizeof(val);
> +}
> +
> /*
> * Query information about a key.
> */
> @@ -407,6 +413,7 @@ static int tpm_key_query(const struct kernel_pkey_params *params,
> struct crypto_akcipher *tfm;
> uint8_t der_pub_key[PUB_KEY_BUF_SIZE];
> uint32_t der_pub_key_len;
> + u8 *pkey, *ptr;
> int len;
>
> /* TPM only works on private keys, public keys still done in software */
> @@ -421,7 +428,16 @@ static int tpm_key_query(const struct kernel_pkey_params *params,
> der_pub_key_len = derive_pub_key(tk->pub_key, tk->pub_key_len,
> der_pub_key);
>
> - ret = crypto_akcipher_set_pub_key(tfm, der_pub_key, der_pub_key_len);
> + pkey = kmalloc(der_pub_key_len + sizeof(u32) * 2, GFP_KERNEL);
> + if (!pkey)
> + goto error_free_tfm;
> + memcpy(pkey, der_pub_key, der_pub_key_len);
> + ptr = pkey + der_pub_key_len;
> + /* Set dummy parameters to satisfy set_pub_key ABI. */
> + ptr = tpm_pack_u32(ptr, 0); /* algo */
> + ptr = tpm_pack_u32(ptr, 0); /* parameter length */
> +
> + ret = crypto_akcipher_set_pub_key(tfm, pkey, der_pub_key_len);
> if (ret < 0)
> goto error_free_tfm;
>
> @@ -440,6 +456,7 @@ static int tpm_key_query(const struct kernel_pkey_params *params,
>
> ret = 0;
> error_free_tfm:
> + kfree(pkey);
> crypto_free_akcipher(tfm);
> pr_devel("<==%s() = %d\n", __func__, ret);
> return ret;
> @@ -460,6 +477,7 @@ static int tpm_key_encrypt(struct tpm_key *tk,
> struct scatterlist in_sg, out_sg;
> uint8_t der_pub_key[PUB_KEY_BUF_SIZE];
> uint32_t der_pub_key_len;
> + u8 *pkey, *ptr;
> int ret;
>
> pr_devel("==>%s()\n", __func__);
> @@ -475,7 +493,15 @@ static int tpm_key_encrypt(struct tpm_key *tk,
> der_pub_key_len = derive_pub_key(tk->pub_key, tk->pub_key_len,
> der_pub_key);
>
> - ret = crypto_akcipher_set_pub_key(tfm, der_pub_key, der_pub_key_len);
> + pkey = kmalloc(der_pub_key_len + sizeof(u32) * 2, GFP_KERNEL);
> + if (!pkey)
> + goto error_free_tfm;
> + memcpy(pkey, der_pub_key, der_pub_key_len);
> + ptr = pkey + der_pub_key_len;
> + ptr = tpm_pack_u32(ptr, 0); /* algo */
> + ptr = tpm_pack_u32(ptr, 0); /* parameter length */
> +
> + ret = crypto_akcipher_set_pub_key(tfm, pkey, der_pub_key_len);
> if (ret < 0)
> goto error_free_tfm;
>
> @@ -500,6 +526,7 @@ static int tpm_key_encrypt(struct tpm_key *tk,
>
> akcipher_request_free(req);
> error_free_tfm:
> + kfree(pkey);
> crypto_free_akcipher(tfm);
> pr_devel("<==%s() = %d\n", __func__, ret);
> return ret;
> @@ -748,6 +775,7 @@ static int tpm_key_verify_signature(const struct key *key,
> char alg_name[CRYPTO_MAX_ALG_NAME];
> uint8_t der_pub_key[PUB_KEY_BUF_SIZE];
> uint32_t der_pub_key_len;
> + u8 *pkey, *ptr;
> int ret;
>
> pr_devel("==>%s()\n", __func__);
> @@ -770,7 +798,15 @@ static int tpm_key_verify_signature(const struct key *key,
> der_pub_key_len = derive_pub_key(tk->pub_key, tk->pub_key_len,
> der_pub_key);
>
> - ret = crypto_akcipher_set_pub_key(tfm, der_pub_key, der_pub_key_len);
> + pkey = kmalloc(der_pub_key_len + sizeof(u32) * 2, GFP_KERNEL);
> + if (!pkey)
> + goto error_free_tfm;
> + memcpy(pkey, der_pub_key, der_pub_key_len);
> + ptr = pkey + der_pub_key_len;
> + ptr = tpm_pack_u32(ptr, 0); /* algo */
> + ptr = tpm_pack_u32(ptr, 0); /* parameter length */
> +
> + ret = crypto_akcipher_set_pub_key(tfm, pkey, der_pub_key_len);
> if (ret < 0)
> goto error_free_tfm;
>
> @@ -792,6 +828,7 @@ static int tpm_key_verify_signature(const struct key *key,
>
> akcipher_request_free(req);
> error_free_tfm:
> + kfree(pkey);
> crypto_free_akcipher(tfm);
> pr_devel("<==%s() = %d\n", __func__, ret);
> if (WARN_ON_ONCE(ret > 0))
> diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
> index 4dcfe281b898..0564951f8760 100644
> --- a/crypto/asymmetric_keys/public_key.c
> +++ b/crypto/asymmetric_keys/public_key.c
> @@ -45,6 +45,7 @@ void public_key_free(struct public_key *key)
> {
> if (key) {
> kfree(key->key);
> + kfree(key->params);
> kfree(key);
> }
> }
> @@ -94,6 +95,12 @@ int software_key_determine_akcipher(const char *encoding,
> return -ENOPKG;
> }
>
> +static u8 *pkey_pack_u32(u8 *dst, u32 val)
> +{
> + memcpy(dst, &val, sizeof(val));
> + return dst + sizeof(val);
> +}
> +
> /*
> * Query information about a key.
> */
> @@ -103,6 +110,7 @@ static int software_key_query(const struct kernel_pkey_params *params,
> struct crypto_akcipher *tfm;
> struct public_key *pkey = params->key->payload.data[asym_crypto];
> char alg_name[CRYPTO_MAX_ALG_NAME];
> + u8 *key, *ptr;
> int ret, len;
>
> ret = software_key_determine_akcipher(params->encoding,
> @@ -115,14 +123,22 @@ static int software_key_query(const struct kernel_pkey_params *params,
> if (IS_ERR(tfm))
> return PTR_ERR(tfm);
>
> + key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
> + GFP_KERNEL);
> + if (!key)
> + goto error_free_tfm;
> + memcpy(key, pkey->key, pkey->keylen);
> + ptr = key + pkey->keylen;
> + ptr = pkey_pack_u32(ptr, pkey->algo);
> + ptr = pkey_pack_u32(ptr, pkey->paramlen);
> + memcpy(ptr, pkey->params, pkey->paramlen);
> +
> if (pkey->key_is_private)
> - ret = crypto_akcipher_set_priv_key(tfm,
> - pkey->key, pkey->keylen);
> + ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen);
> else
> - ret = crypto_akcipher_set_pub_key(tfm,
> - pkey->key, pkey->keylen);
> + ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen);
> if (ret < 0)
> - goto error_free_tfm;
> + goto error_free_key;
>
> len = crypto_akcipher_maxsize(tfm);
> info->key_size = len * 8;
> @@ -143,6 +159,8 @@ static int software_key_query(const struct kernel_pkey_params *params,
> }
> ret = 0;
>
> +error_free_key:
> + kfree(key);
> error_free_tfm:
> crypto_free_akcipher(tfm);
> pr_devel("<==%s() = %d\n", __func__, ret);
> @@ -161,6 +179,7 @@ static int software_key_eds_op(struct kernel_pkey_params *params,
> struct crypto_wait cwait;
> struct scatterlist in_sg, out_sg;
> char alg_name[CRYPTO_MAX_ALG_NAME];
> + char *key, *ptr;
> int ret;
>
> pr_devel("==>%s()\n", __func__);
> @@ -179,14 +198,23 @@ static int software_key_eds_op(struct kernel_pkey_params *params,
> if (!req)
> goto error_free_tfm;
>
> + key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
> + GFP_KERNEL);
> + if (!key)
> + goto error_free_req;
> +
> + memcpy(key, pkey->key, pkey->keylen);
> + ptr = key + pkey->keylen;
> + ptr = pkey_pack_u32(ptr, pkey->algo);
> + ptr = pkey_pack_u32(ptr, pkey->paramlen);
> + memcpy(ptr, pkey->params, pkey->paramlen);
> +
> if (pkey->key_is_private)
> - ret = crypto_akcipher_set_priv_key(tfm,
> - pkey->key, pkey->keylen);
> + ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen);
> else
> - ret = crypto_akcipher_set_pub_key(tfm,
> - pkey->key, pkey->keylen);
> + ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen);
> if (ret)
> - goto error_free_req;
> + goto error_free_key;
>
> sg_init_one(&in_sg, in, params->in_len);
> sg_init_one(&out_sg, out, params->out_len);
> @@ -216,6 +244,8 @@ static int software_key_eds_op(struct kernel_pkey_params *params,
> if (ret == 0)
> ret = req->dst_len;
>
> +error_free_key:
> + kfree(key);
> error_free_req:
> akcipher_request_free(req);
> error_free_tfm:
> @@ -235,6 +265,7 @@ int public_key_verify_signature(const struct public_key *pkey,
> struct akcipher_request *req;
> struct scatterlist src_sg[2];
> char alg_name[CRYPTO_MAX_ALG_NAME];
> + char *key, *ptr;
> int ret;
>
> pr_devel("==>%s()\n", __func__);
> @@ -258,14 +289,23 @@ int public_key_verify_signature(const struct public_key *pkey,
> if (!req)
> goto error_free_tfm;
>
> + key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
> + GFP_KERNEL);
> + if (!key)
> + goto error_free_req;
> +
> + memcpy(key, pkey->key, pkey->keylen);
> + ptr = key + pkey->keylen;
> + ptr = pkey_pack_u32(ptr, pkey->algo);
> + ptr = pkey_pack_u32(ptr, pkey->paramlen);
> + memcpy(ptr, pkey->params, pkey->paramlen);
> +
> if (pkey->key_is_private)
> - ret = crypto_akcipher_set_priv_key(tfm,
> - pkey->key, pkey->keylen);
> + ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen);
> else
> - ret = crypto_akcipher_set_pub_key(tfm,
> - pkey->key, pkey->keylen);
> + ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen);
> if (ret)
> - goto error_free_req;
> + goto error_free_key;
>
> sg_init_table(src_sg, 2);
> sg_set_buf(&src_sg[0], sig->s, sig->s_size);
> @@ -278,6 +318,8 @@ int public_key_verify_signature(const struct public_key *pkey,
> crypto_req_done, &cwait);
> ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait);
>
> +error_free_key:
> + kfree(key);
> error_free_req:
> akcipher_request_free(req);
> error_free_tfm:
> diff --git a/crypto/asymmetric_keys/x509.asn1 b/crypto/asymmetric_keys/x509.asn1
> index aae0cde414e2..5c9f4e4a5231 100644
> --- a/crypto/asymmetric_keys/x509.asn1
> +++ b/crypto/asymmetric_keys/x509.asn1
> @@ -22,7 +22,7 @@ CertificateSerialNumber ::= INTEGER
>
> AlgorithmIdentifier ::= SEQUENCE {
> algorithm OBJECT IDENTIFIER ({ x509_note_OID }),
> - parameters ANY OPTIONAL
> + parameters ANY OPTIONAL ({ x509_note_params })
> }
>
> Name ::= SEQUENCE OF RelativeDistinguishedName
> diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
> index 991f4d735a4e..b2cdf2db1987 100644
> --- a/crypto/asymmetric_keys/x509_cert_parser.c
> +++ b/crypto/asymmetric_keys/x509_cert_parser.c
> @@ -26,6 +26,9 @@ struct x509_parse_context {
> const void *cert_start; /* Start of cert content */
> const void *key; /* Key data */
> size_t key_size; /* Size of key data */
> + const void *params; /* Key parameters */
> + size_t params_size; /* Size of key parameters */
> + enum OID key_algo; /* Public key algorithm */
> enum OID last_oid; /* Last OID encountered */
> enum OID algo_oid; /* Algorithm OID */
> unsigned char nr_mpi; /* Number of MPIs stored */
> @@ -109,6 +112,13 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
>
> cert->pub->keylen = ctx->key_size;
>
> + cert->pub->params = kmemdup(ctx->params, ctx->params_size, GFP_KERNEL);
> + if (!cert->pub->params)
> + goto error_decode;
> +
> + cert->pub->paramlen = ctx->params_size;
> + cert->pub->algo = ctx->key_algo;
> +
> /* Grab the signature bits */
> ret = x509_get_sig_params(cert);
> if (ret < 0)
> @@ -401,6 +411,27 @@ int x509_note_subject(void *context, size_t hdrlen,
> }
>
> /*
> + * Extract the parameters for the public key
> + */
> +int x509_note_params(void *context, size_t hdrlen,
> + unsigned char tag,
> + const void *value, size_t vlen)
> +{
> + struct x509_parse_context *ctx = context;
> +
> + /*
> + * AlgorithmIdentifier is used three times in the x509, we should skip
> + * first and ignore third, using second one which is after subject and
> + * before subjectPublicKey.
> + */
> + if (!ctx->cert->raw_subject || ctx->key)
> + return 0;
> + ctx->params = value - hdrlen;
> + ctx->params_size = vlen + hdrlen;
> + return 0;
> +}
> +
> +/*
> * Extract the data for the public key algorithm
> */
> int x509_extract_key_data(void *context, size_t hdrlen,
> diff --git a/crypto/testmgr.c b/crypto/testmgr.c
> index 443d5b6f1045..50396b3a2a47 100644
> --- a/crypto/testmgr.c
> +++ b/crypto/testmgr.c
> @@ -2493,6 +2493,12 @@ static int alg_test_kpp(const struct alg_test_desc *desc, const char *driver,
> return err;
> }
>
> +static u8 *test_pack_u32(u8 *dst, u32 val)
> +{
> + memcpy(dst, &val, sizeof(val));
> + return dst + sizeof(val);
> +}
> +
> static int test_akcipher_one(struct crypto_akcipher *tfm,
> const struct akcipher_testvec *vecs)
> {
> @@ -2507,6 +2513,7 @@ static int test_akcipher_one(struct crypto_akcipher *tfm,
> const char *m, *c;
> unsigned int m_size, c_size;
> const char *op;
> + u8 *key, *ptr;
>
> if (testmgr_alloc_buf(xbuf))
> return err;
> @@ -2517,12 +2524,20 @@ static int test_akcipher_one(struct crypto_akcipher *tfm,
>
> crypto_init_wait(&wait);
>
> + key = kmalloc(vecs->key_len + sizeof(u32) * 2 + vecs->param_len,
> + GFP_KERNEL);
> + if (!key)
> + goto free_xbuf;
> + memcpy(key, vecs->key, vecs->key_len);
> + ptr = key + vecs->key_len;
> + ptr = test_pack_u32(ptr, vecs->algo);
> + ptr = test_pack_u32(ptr, vecs->param_len);
> + memcpy(ptr, vecs->params, vecs->param_len);
> +
> if (vecs->public_key_vec)
> - err = crypto_akcipher_set_pub_key(tfm, vecs->key,
> - vecs->key_len);
> + err = crypto_akcipher_set_pub_key(tfm, key, vecs->key_len);
> else
> - err = crypto_akcipher_set_priv_key(tfm, vecs->key,
> - vecs->key_len);
> + err = crypto_akcipher_set_priv_key(tfm, key, vecs->key_len);
> if (err)
> goto free_req;
>
> @@ -2652,6 +2667,7 @@ static int test_akcipher_one(struct crypto_akcipher *tfm,
> kfree(outbuf_enc);
> free_req:
> akcipher_request_free(req);
> + kfree(key);
> free_xbuf:
> testmgr_free_buf(xbuf);
> return err;
> diff --git a/crypto/testmgr.h b/crypto/testmgr.h
> index f267633cf13a..75d8f8c3e203 100644
> --- a/crypto/testmgr.h
> +++ b/crypto/testmgr.h
> @@ -25,6 +25,8 @@
> #ifndef _CRYPTO_TESTMGR_H
> #define _CRYPTO_TESTMGR_H
>
> +#include <linux/oid_registry.h>
> +
> #define MAX_IVLEN 32
>
> /*
> @@ -135,13 +137,16 @@ struct drbg_testvec {
>
> struct akcipher_testvec {
> const unsigned char *key;
> + const unsigned char *params;
> const unsigned char *m;
> const unsigned char *c;
> unsigned int key_len;
> + unsigned int param_len;
> unsigned int m_size;
> unsigned int c_size;
> bool public_key_vec;
> bool siggen_sigver_test;
> + enum OID algo;
> };
>
> struct kpp_testvec {
> diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h
> index 28ffa9ef03a9..4ecbedddd9a1 100644
> --- a/include/crypto/akcipher.h
> +++ b/include/crypto/akcipher.h
> @@ -74,10 +74,10 @@ struct crypto_akcipher {
> * operation
> * @set_pub_key: Function invokes the algorithm specific set public key
> * function, which knows how to decode and interpret
> - * the BER encoded public key
> + * the BER encoded public key and parameters
> * @set_priv_key: Function invokes the algorithm specific set private key
> * function, which knows how to decode and interpret
> - * the BER encoded private key
> + * the BER encoded private key and parameters
> * @max_size: Function returns dest buffer size required for a given key.
> * @init: Initialize the cryptographic transformation object.
> * This function is used to initialize the cryptographic
> @@ -388,11 +388,12 @@ static inline int crypto_akcipher_verify(struct akcipher_request *req)
> * crypto_akcipher_set_pub_key() - Invoke set public key operation
> *
> * Function invokes the algorithm specific set key function, which knows
> - * how to decode and interpret the encoded key
> + * how to decode and interpret the encoded key and parameters
> *
> * @tfm: tfm handle
> - * @key: BER encoded public key
> - * @keylen: length of the key
> + * @key: BER encoded public key, algo OID, paramlen, BER encoded
> + * parameters
> + * @keylen: length of the key (not including other data)
> *
> * Return: zero on success; error code in case of error
> */
> @@ -409,11 +410,12 @@ static inline int crypto_akcipher_set_pub_key(struct crypto_akcipher *tfm,
> * crypto_akcipher_set_priv_key() - Invoke set private key operation
> *
> * Function invokes the algorithm specific set key function, which knows
> - * how to decode and interpret the encoded key
> + * how to decode and interpret the encoded keya and parameters
> *
> * @tfm: tfm handle
> - * @key: BER encoded private key
> - * @keylen: length of the key
> + * @key: BER encoded private key, algo OID, paramlen, BER encoded
> + * parameters
> + * @keylen: length of the key (not including other data)
> *
> * Return: zero on success; error code in case of error
> */
> diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
> index be626eac9113..712fe1214b5f 100644
> --- a/include/crypto/public_key.h
> +++ b/include/crypto/public_key.h
> @@ -15,6 +15,7 @@
> #define _LINUX_PUBLIC_KEY_H
>
> #include <linux/keyctl.h>
> +#include <linux/oid_registry.h>
>
> /*
> * Cryptographic data for the public-key subtype of the asymmetric key type.
> @@ -25,6 +26,9 @@
> struct public_key {
> void *key;
> u32 keylen;
> + enum OID algo;
> + void *params;
> + u32 paramlen;
> bool key_is_private;
> const char *id_type;
> const char *pkey_algo;
> --
> 2.11.0

2019-03-22 20:27:56

by Gary R Hook

[permalink] [raw]
Subject: Re: [PATCH v7 03/11] crypto: rsa - unimplement sign/verify for raw RSA backends

On 3/22/19 2:21 PM, Vitaly Chikunov wrote:
> Giovanni Cabiddu,
>
> Can you Ack this patch as it includes small change to QAT driver.
>
> Tom Lendacky, Gary Hook,
>
> Can you Ack this patch as it includes small change to CCP driver.
>
> Horia Geantă, Aymen Sghaier,
>
> Can you Ack this patch as it includes small change to CAAM driver.
>
> Thanks,
>
> On Fri, Mar 01, 2019 at 08:59:10PM +0300, Vitaly Chikunov wrote:
>> In preparation for new akcipher verify call remove sign/verify callbacks
>> from RSA backends and make PKCS1 driver call encrypt/decrypt instead.
>>
>> This also complies with the well-known idea that raw RSA should never be
>> used for sign/verify. It only should be used with proper padding scheme
>> such as PKCS1 driver provides.
>>
>> Cc: Giovanni Cabiddu <[email protected]>
>> Cc: [email protected]
>> Cc: Tom Lendacky <[email protected]>
>> Cc: Gary Hook <[email protected]>
>> Cc: Horia Geantă <[email protected]>
>> Cc: Aymen Sghaier <[email protected]>
>> Signed-off-by: Vitaly Chikunov <[email protected]>

Acked-by: Gary R Hook <[email protected]>

>> ---
>> crypto/rsa-pkcs1pad.c | 4 +-
>> crypto/rsa.c | 109 --------------------------
>> drivers/crypto/caam/caampkc.c | 2 -
>> drivers/crypto/ccp/ccp-crypto-rsa.c | 2 -
>> drivers/crypto/qat/qat_common/qat_asym_algs.c | 2 -
>> 5 files changed, 2 insertions(+), 117 deletions(-)
>>
>> diff --git a/crypto/rsa-pkcs1pad.c b/crypto/rsa-pkcs1pad.c
>> index 0a6680ca8cb6..94382fa2c6ac 100644
>> --- a/crypto/rsa-pkcs1pad.c
>> +++ b/crypto/rsa-pkcs1pad.c
>> @@ -429,7 +429,7 @@ static int pkcs1pad_sign(struct akcipher_request *req)
>> akcipher_request_set_crypt(&req_ctx->child_req, req_ctx->in_sg,
>> req->dst, ctx->key_size - 1, req->dst_len);
>>
>> - err = crypto_akcipher_sign(&req_ctx->child_req);
>> + err = crypto_akcipher_decrypt(&req_ctx->child_req);
>> if (err != -EINPROGRESS && err != -EBUSY)
>> return pkcs1pad_encrypt_sign_complete(req, err);
>>
>> @@ -551,7 +551,7 @@ static int pkcs1pad_verify(struct akcipher_request *req)
>> req_ctx->out_sg, req->src_len,
>> ctx->key_size);
>>
>> - err = crypto_akcipher_verify(&req_ctx->child_req);
>> + err = crypto_akcipher_encrypt(&req_ctx->child_req);
>> if (err != -EINPROGRESS && err != -EBUSY)
>> return pkcs1pad_verify_complete(req, err);
>>
>> diff --git a/crypto/rsa.c b/crypto/rsa.c
>> index 4167980c243d..5d427c1100d6 100644
>> --- a/crypto/rsa.c
>> +++ b/crypto/rsa.c
>> @@ -50,34 +50,6 @@ static int _rsa_dec(const struct rsa_mpi_key *key, MPI m, MPI c)
>> return mpi_powm(m, c, key->d, key->n);
>> }
>>
>> -/*
>> - * RSASP1 function [RFC3447 sec 5.2.1]
>> - * s = m^d mod n
>> - */
>> -static int _rsa_sign(const struct rsa_mpi_key *key, MPI s, MPI m)
>> -{
>> - /* (1) Validate 0 <= m < n */
>> - if (mpi_cmp_ui(m, 0) < 0 || mpi_cmp(m, key->n) >= 0)
>> - return -EINVAL;
>> -
>> - /* (2) s = m^d mod n */
>> - return mpi_powm(s, m, key->d, key->n);
>> -}
>> -
>> -/*
>> - * RSAVP1 function [RFC3447 sec 5.2.2]
>> - * m = s^e mod n;
>> - */
>> -static int _rsa_verify(const struct rsa_mpi_key *key, MPI m, MPI s)
>> -{
>> - /* (1) Validate 0 <= s < n */
>> - if (mpi_cmp_ui(s, 0) < 0 || mpi_cmp(s, key->n) >= 0)
>> - return -EINVAL;
>> -
>> - /* (2) m = s^e mod n */
>> - return mpi_powm(m, s, key->e, key->n);
>> -}
>> -
>> static inline struct rsa_mpi_key *rsa_get_key(struct crypto_akcipher *tfm)
>> {
>> return akcipher_tfm_ctx(tfm);
>> @@ -160,85 +132,6 @@ static int rsa_dec(struct akcipher_request *req)
>> return ret;
>> }
>>
>> -static int rsa_sign(struct akcipher_request *req)
>> -{
>> - struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
>> - const struct rsa_mpi_key *pkey = rsa_get_key(tfm);
>> - MPI m, s = mpi_alloc(0);
>> - int ret = 0;
>> - int sign;
>> -
>> - if (!s)
>> - return -ENOMEM;
>> -
>> - if (unlikely(!pkey->n || !pkey->d)) {
>> - ret = -EINVAL;
>> - goto err_free_s;
>> - }
>> -
>> - ret = -ENOMEM;
>> - m = mpi_read_raw_from_sgl(req->src, req->src_len);
>> - if (!m)
>> - goto err_free_s;
>> -
>> - ret = _rsa_sign(pkey, s, m);
>> - if (ret)
>> - goto err_free_m;
>> -
>> - ret = mpi_write_to_sgl(s, req->dst, req->dst_len, &sign);
>> - if (ret)
>> - goto err_free_m;
>> -
>> - if (sign < 0)
>> - ret = -EBADMSG;
>> -
>> -err_free_m:
>> - mpi_free(m);
>> -err_free_s:
>> - mpi_free(s);
>> - return ret;
>> -}
>> -
>> -static int rsa_verify(struct akcipher_request *req)
>> -{
>> - struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
>> - const struct rsa_mpi_key *pkey = rsa_get_key(tfm);
>> - MPI s, m = mpi_alloc(0);
>> - int ret = 0;
>> - int sign;
>> -
>> - if (!m)
>> - return -ENOMEM;
>> -
>> - if (unlikely(!pkey->n || !pkey->e)) {
>> - ret = -EINVAL;
>> - goto err_free_m;
>> - }
>> -
>> - s = mpi_read_raw_from_sgl(req->src, req->src_len);
>> - if (!s) {
>> - ret = -ENOMEM;
>> - goto err_free_m;
>> - }
>> -
>> - ret = _rsa_verify(pkey, m, s);
>> - if (ret)
>> - goto err_free_s;
>> -
>> - ret = mpi_write_to_sgl(m, req->dst, req->dst_len, &sign);
>> - if (ret)
>> - goto err_free_s;
>> -
>> - if (sign < 0)
>> - ret = -EBADMSG;
>> -
>> -err_free_s:
>> - mpi_free(s);
>> -err_free_m:
>> - mpi_free(m);
>> - return ret;
>> -}
>> -
>> static void rsa_free_mpi_key(struct rsa_mpi_key *key)
>> {
>> mpi_free(key->d);
>> @@ -353,8 +246,6 @@ static void rsa_exit_tfm(struct crypto_akcipher *tfm)
>> static struct akcipher_alg rsa = {
>> .encrypt = rsa_enc,
>> .decrypt = rsa_dec,
>> - .sign = rsa_sign,
>> - .verify = rsa_verify,
>> .set_priv_key = rsa_set_priv_key,
>> .set_pub_key = rsa_set_pub_key,
>> .max_size = rsa_max_size,
>> diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c
>> index 77ab28a2811a..d7e1fc5bacc5 100644
>> --- a/drivers/crypto/caam/caampkc.c
>> +++ b/drivers/crypto/caam/caampkc.c
>> @@ -994,8 +994,6 @@ static void caam_rsa_exit_tfm(struct crypto_akcipher *tfm)
>> static struct akcipher_alg caam_rsa = {
>> .encrypt = caam_rsa_enc,
>> .decrypt = caam_rsa_dec,
>> - .sign = caam_rsa_dec,
>> - .verify = caam_rsa_enc,
>> .set_pub_key = caam_rsa_set_pub_key,
>> .set_priv_key = caam_rsa_set_priv_key,
>> .max_size = caam_rsa_max_size,
>> diff --git a/drivers/crypto/ccp/ccp-crypto-rsa.c b/drivers/crypto/ccp/ccp-crypto-rsa.c
>> index 05850dfd7940..71e40680c880 100644
>> --- a/drivers/crypto/ccp/ccp-crypto-rsa.c
>> +++ b/drivers/crypto/ccp/ccp-crypto-rsa.c
>> @@ -214,8 +214,6 @@ static void ccp_rsa_exit_tfm(struct crypto_akcipher *tfm)
>> static struct akcipher_alg ccp_rsa_defaults = {
>> .encrypt = ccp_rsa_encrypt,
>> .decrypt = ccp_rsa_decrypt,
>> - .sign = ccp_rsa_decrypt,
>> - .verify = ccp_rsa_encrypt,
>> .set_pub_key = ccp_rsa_setpubkey,
>> .set_priv_key = ccp_rsa_setprivkey,
>> .max_size = ccp_rsa_maxsize,
>> diff --git a/drivers/crypto/qat/qat_common/qat_asym_algs.c b/drivers/crypto/qat/qat_common/qat_asym_algs.c
>> index 320e7854b4ee..c05d03565e96 100644
>> --- a/drivers/crypto/qat/qat_common/qat_asym_algs.c
>> +++ b/drivers/crypto/qat/qat_common/qat_asym_algs.c
>> @@ -1300,8 +1300,6 @@ static void qat_rsa_exit_tfm(struct crypto_akcipher *tfm)
>> static struct akcipher_alg rsa = {
>> .encrypt = qat_rsa_enc,
>> .decrypt = qat_rsa_dec,
>> - .sign = qat_rsa_dec,
>> - .verify = qat_rsa_enc,
>> .set_pub_key = qat_rsa_setpubkey,
>> .set_priv_key = qat_rsa_setprivkey,
>> .max_size = qat_rsa_max_size,
>> --
>> 2.11.0

2019-03-22 22:41:18

by Horia Geanta

[permalink] [raw]
Subject: Re: [PATCH v7 03/11] crypto: rsa - unimplement sign/verify for raw RSA backends

On 3/1/2019 7:59 PM, Vitaly Chikunov wrote:
> In preparation for new akcipher verify call remove sign/verify callbacks
> from RSA backends and make PKCS1 driver call encrypt/decrypt instead.
>
> This also complies with the well-known idea that raw RSA should never be
> used for sign/verify. It only should be used with proper padding scheme
> such as PKCS1 driver provides.
>
> Cc: Giovanni Cabiddu <[email protected]>
> Cc: [email protected]
> Cc: Tom Lendacky <[email protected]>
> Cc: Gary Hook <[email protected]>
> Cc: Horia Geant? <[email protected]>
> Cc: Aymen Sghaier <[email protected]>
> Signed-off-by: Vitaly Chikunov <[email protected]>
Reviewed-by: Horia Geant? <[email protected]>

Thanks,
Horia