diff options
author | Vitaly Chikunov <vt@altlinux.org> | 2019-04-11 11:51:15 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2019-04-18 10:15:02 -0400 |
commit | c7381b01287240abe942a081729203e26782d981 (patch) | |
tree | f70bd59c5b8b110b9116d1660d5fe03033ed3596 | |
parent | 3ecc97259934489e7e03cbeb1d70f6a23cccb3ae (diff) |
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 and its return value inspected.
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 <dhowells@redhat.com>
Cc: keyrings@vger.kernel.org
Signed-off-by: Vitaly Chikunov <vt@altlinux.org>
Reviewed-by: Denis Kenzior <denkenz@gmail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r-- | crypto/asymmetric_keys/asym_tpm.c | 34 | ||||
-rw-r--r-- | crypto/asymmetric_keys/public_key.c | 34 | ||||
-rw-r--r-- | crypto/rsa-pkcs1pad.c | 29 | ||||
-rw-r--r-- | crypto/testmgr.c | 50 | ||||
-rw-r--r-- | include/crypto/akcipher.h | 36 |
5 files changed, 92 insertions, 91 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, | |||
744 | struct crypto_wait cwait; | 744 | struct crypto_wait cwait; |
745 | struct crypto_akcipher *tfm; | 745 | struct crypto_akcipher *tfm; |
746 | struct akcipher_request *req; | 746 | struct akcipher_request *req; |
747 | struct scatterlist sig_sg, digest_sg; | 747 | struct scatterlist src_sg[2]; |
748 | char alg_name[CRYPTO_MAX_ALG_NAME]; | 748 | char alg_name[CRYPTO_MAX_ALG_NAME]; |
749 | uint8_t der_pub_key[PUB_KEY_BUF_SIZE]; | 749 | uint8_t der_pub_key[PUB_KEY_BUF_SIZE]; |
750 | uint32_t der_pub_key_len; | 750 | uint32_t der_pub_key_len; |
751 | void *output; | 751 | void *digest; |
752 | unsigned int outlen; | ||
753 | int ret; | 752 | int ret; |
754 | 753 | ||
755 | pr_devel("==>%s()\n", __func__); | 754 | pr_devel("==>%s()\n", __func__); |
@@ -782,35 +781,22 @@ static int tpm_key_verify_signature(const struct key *key, | |||
782 | goto error_free_tfm; | 781 | goto error_free_tfm; |
783 | 782 | ||
784 | ret = -ENOMEM; | 783 | ret = -ENOMEM; |
785 | outlen = crypto_akcipher_maxsize(tfm); | 784 | digest = kmemdup(sig->digest, sig->digest_size, GFP_KERNEL); |
786 | output = kmalloc(outlen, GFP_KERNEL); | 785 | if (!digest) |
787 | if (!output) | ||
788 | goto error_free_req; | 786 | goto error_free_req; |
789 | 787 | ||
790 | sg_init_one(&sig_sg, sig->s, sig->s_size); | 788 | sg_init_table(src_sg, 2); |
791 | sg_init_one(&digest_sg, output, outlen); | 789 | sg_set_buf(&src_sg[0], sig->s, sig->s_size); |
792 | akcipher_request_set_crypt(req, &sig_sg, &digest_sg, sig->s_size, | 790 | sg_set_buf(&src_sg[1], digest, sig->digest_size); |
793 | outlen); | 791 | akcipher_request_set_crypt(req, src_sg, NULL, sig->s_size, |
792 | sig->digest_size); | ||
794 | crypto_init_wait(&cwait); | 793 | crypto_init_wait(&cwait); |
795 | akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | | 794 | akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | |
796 | CRYPTO_TFM_REQ_MAY_SLEEP, | 795 | CRYPTO_TFM_REQ_MAY_SLEEP, |
797 | crypto_req_done, &cwait); | 796 | crypto_req_done, &cwait); |
798 | |||
799 | /* Perform the verification calculation. This doesn't actually do the | ||
800 | * verification, but rather calculates the hash expected by the | ||
801 | * signature and returns that to us. | ||
802 | */ | ||
803 | ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait); | 797 | ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait); |
804 | if (ret) | ||
805 | goto out_free_output; | ||
806 | |||
807 | /* Do the actual verification step. */ | ||
808 | if (req->dst_len != sig->digest_size || | ||
809 | memcmp(sig->digest, output, sig->digest_size) != 0) | ||
810 | ret = -EKEYREJECTED; | ||
811 | 798 | ||
812 | out_free_output: | 799 | kfree(digest); |
813 | kfree(output); | ||
814 | error_free_req: | 800 | error_free_req: |
815 | akcipher_request_free(req); | 801 | akcipher_request_free(req); |
816 | error_free_tfm: | 802 | error_free_tfm: |
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c index f5d85b47fcc6..0c069fe8a59c 100644 --- a/crypto/asymmetric_keys/public_key.c +++ b/crypto/asymmetric_keys/public_key.c | |||
@@ -227,10 +227,9 @@ int public_key_verify_signature(const struct public_key *pkey, | |||
227 | struct crypto_wait cwait; | 227 | struct crypto_wait cwait; |
228 | struct crypto_akcipher *tfm; | 228 | struct crypto_akcipher *tfm; |
229 | struct akcipher_request *req; | 229 | struct akcipher_request *req; |
230 | struct scatterlist sig_sg, digest_sg; | 230 | struct scatterlist src_sg[2]; |
231 | char alg_name[CRYPTO_MAX_ALG_NAME]; | 231 | char alg_name[CRYPTO_MAX_ALG_NAME]; |
232 | void *output; | 232 | void *digest; |
233 | unsigned int outlen; | ||
234 | int ret; | 233 | int ret; |
235 | 234 | ||
236 | pr_devel("==>%s()\n", __func__); | 235 | pr_devel("==>%s()\n", __func__); |
@@ -264,35 +263,22 @@ int public_key_verify_signature(const struct public_key *pkey, | |||
264 | goto error_free_req; | 263 | goto error_free_req; |
265 | 264 | ||
266 | ret = -ENOMEM; | 265 | ret = -ENOMEM; |
267 | outlen = crypto_akcipher_maxsize(tfm); | 266 | digest = kmemdup(sig->digest, sig->digest_size, GFP_KERNEL); |
268 | output = kmalloc(outlen, GFP_KERNEL); | 267 | if (!digest) |
269 | if (!output) | ||
270 | goto error_free_req; | 268 | goto error_free_req; |
271 | 269 | ||
272 | sg_init_one(&sig_sg, sig->s, sig->s_size); | 270 | sg_init_table(src_sg, 2); |
273 | sg_init_one(&digest_sg, output, outlen); | 271 | sg_set_buf(&src_sg[0], sig->s, sig->s_size); |
274 | akcipher_request_set_crypt(req, &sig_sg, &digest_sg, sig->s_size, | 272 | sg_set_buf(&src_sg[1], digest, sig->digest_size); |
275 | outlen); | 273 | akcipher_request_set_crypt(req, src_sg, NULL, sig->s_size, |
274 | sig->digest_size); | ||
276 | crypto_init_wait(&cwait); | 275 | crypto_init_wait(&cwait); |
277 | akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | | 276 | akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | |
278 | CRYPTO_TFM_REQ_MAY_SLEEP, | 277 | CRYPTO_TFM_REQ_MAY_SLEEP, |
279 | crypto_req_done, &cwait); | 278 | crypto_req_done, &cwait); |
280 | |||
281 | /* Perform the verification calculation. This doesn't actually do the | ||
282 | * verification, but rather calculates the hash expected by the | ||
283 | * signature and returns that to us. | ||
284 | */ | ||
285 | ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait); | 279 | ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait); |
286 | if (ret) | ||
287 | goto out_free_output; | ||
288 | |||
289 | /* Do the actual verification step. */ | ||
290 | if (req->dst_len != sig->digest_size || | ||
291 | memcmp(sig->digest, output, sig->digest_size) != 0) | ||
292 | ret = -EKEYREJECTED; | ||
293 | 280 | ||
294 | out_free_output: | 281 | kfree(digest); |
295 | kfree(output); | ||
296 | error_free_req: | 282 | error_free_req: |
297 | akcipher_request_free(req); | 283 | akcipher_request_free(req); |
298 | error_free_tfm: | 284 | 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) | |||
488 | 488 | ||
489 | err = 0; | 489 | err = 0; |
490 | 490 | ||
491 | if (req->dst_len < dst_len - pos) | 491 | if (req->dst_len != dst_len - pos) { |
492 | err = -EOVERFLOW; | 492 | err = -EKEYREJECTED; |
493 | req->dst_len = dst_len - pos; | 493 | req->dst_len = dst_len - pos; |
494 | 494 | goto done; | |
495 | if (!err) | 495 | } |
496 | sg_copy_from_buffer(req->dst, | 496 | /* Extract appended digest. */ |
497 | sg_nents_for_len(req->dst, req->dst_len), | 497 | sg_pcopy_to_buffer(req->src, |
498 | out_buf + pos, req->dst_len); | 498 | sg_nents_for_len(req->src, |
499 | req->src_len + req->dst_len), | ||
500 | req_ctx->out_buf + ctx->key_size, | ||
501 | req->dst_len, ctx->key_size); | ||
502 | /* Do the actual verification step. */ | ||
503 | if (memcmp(req_ctx->out_buf + ctx->key_size, out_buf + pos, | ||
504 | req->dst_len) != 0) | ||
505 | err = -EKEYREJECTED; | ||
499 | done: | 506 | done: |
500 | kzfree(req_ctx->out_buf); | 507 | kzfree(req_ctx->out_buf); |
501 | 508 | ||
@@ -532,10 +539,12 @@ static int pkcs1pad_verify(struct akcipher_request *req) | |||
532 | struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); | 539 | struct pkcs1pad_request *req_ctx = akcipher_request_ctx(req); |
533 | int err; | 540 | int err; |
534 | 541 | ||
535 | if (!ctx->key_size || req->src_len < ctx->key_size) | 542 | if (WARN_ON(req->dst) || |
543 | WARN_ON(!req->dst_len) || | ||
544 | !ctx->key_size || req->src_len < ctx->key_size) | ||
536 | return -EINVAL; | 545 | return -EINVAL; |
537 | 546 | ||
538 | req_ctx->out_buf = kmalloc(ctx->key_size, GFP_KERNEL); | 547 | req_ctx->out_buf = kmalloc(ctx->key_size + req->dst_len, GFP_KERNEL); |
539 | if (!req_ctx->out_buf) | 548 | if (!req_ctx->out_buf) |
540 | return -ENOMEM; | 549 | return -ENOMEM; |
541 | 550 | ||
diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 0f6bfb6ce6a4..21b27996508a 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c | |||
@@ -2595,7 +2595,7 @@ static int test_akcipher_one(struct crypto_akcipher *tfm, | |||
2595 | struct crypto_wait wait; | 2595 | struct crypto_wait wait; |
2596 | unsigned int out_len_max, out_len = 0; | 2596 | unsigned int out_len_max, out_len = 0; |
2597 | int err = -ENOMEM; | 2597 | int err = -ENOMEM; |
2598 | struct scatterlist src, dst, src_tab[2]; | 2598 | struct scatterlist src, dst, src_tab[3]; |
2599 | const char *m, *c; | 2599 | const char *m, *c; |
2600 | unsigned int m_size, c_size; | 2600 | unsigned int m_size, c_size; |
2601 | const char *op; | 2601 | const char *op; |
@@ -2618,13 +2618,12 @@ static int test_akcipher_one(struct crypto_akcipher *tfm, | |||
2618 | if (err) | 2618 | if (err) |
2619 | goto free_req; | 2619 | goto free_req; |
2620 | 2620 | ||
2621 | err = -ENOMEM; | ||
2622 | out_len_max = crypto_akcipher_maxsize(tfm); | ||
2623 | |||
2624 | /* | 2621 | /* |
2625 | * First run test which do not require a private key, such as | 2622 | * First run test which do not require a private key, such as |
2626 | * encrypt or verify. | 2623 | * encrypt or verify. |
2627 | */ | 2624 | */ |
2625 | err = -ENOMEM; | ||
2626 | out_len_max = crypto_akcipher_maxsize(tfm); | ||
2628 | outbuf_enc = kzalloc(out_len_max, GFP_KERNEL); | 2627 | outbuf_enc = kzalloc(out_len_max, GFP_KERNEL); |
2629 | if (!outbuf_enc) | 2628 | if (!outbuf_enc) |
2630 | goto free_req; | 2629 | goto free_req; |
@@ -2650,12 +2649,20 @@ static int test_akcipher_one(struct crypto_akcipher *tfm, | |||
2650 | goto free_all; | 2649 | goto free_all; |
2651 | memcpy(xbuf[0], m, m_size); | 2650 | memcpy(xbuf[0], m, m_size); |
2652 | 2651 | ||
2653 | sg_init_table(src_tab, 2); | 2652 | sg_init_table(src_tab, 3); |
2654 | sg_set_buf(&src_tab[0], xbuf[0], 8); | 2653 | sg_set_buf(&src_tab[0], xbuf[0], 8); |
2655 | sg_set_buf(&src_tab[1], xbuf[0] + 8, m_size - 8); | 2654 | sg_set_buf(&src_tab[1], xbuf[0] + 8, m_size - 8); |
2656 | sg_init_one(&dst, outbuf_enc, out_len_max); | 2655 | if (vecs->siggen_sigver_test) { |
2657 | akcipher_request_set_crypt(req, src_tab, &dst, m_size, | 2656 | if (WARN_ON(c_size > PAGE_SIZE)) |
2658 | out_len_max); | 2657 | goto free_all; |
2658 | memcpy(xbuf[1], c, c_size); | ||
2659 | sg_set_buf(&src_tab[2], xbuf[1], c_size); | ||
2660 | akcipher_request_set_crypt(req, src_tab, NULL, m_size, c_size); | ||
2661 | } else { | ||
2662 | sg_init_one(&dst, outbuf_enc, out_len_max); | ||
2663 | akcipher_request_set_crypt(req, src_tab, &dst, m_size, | ||
2664 | out_len_max); | ||
2665 | } | ||
2659 | akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, | 2666 | akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, |
2660 | crypto_req_done, &wait); | 2667 | crypto_req_done, &wait); |
2661 | 2668 | ||
@@ -2668,18 +2675,21 @@ static int test_akcipher_one(struct crypto_akcipher *tfm, | |||
2668 | pr_err("alg: akcipher: %s test failed. err %d\n", op, err); | 2675 | pr_err("alg: akcipher: %s test failed. err %d\n", op, err); |
2669 | goto free_all; | 2676 | goto free_all; |
2670 | } | 2677 | } |
2671 | if (req->dst_len != c_size) { | 2678 | if (!vecs->siggen_sigver_test) { |
2672 | pr_err("alg: akcipher: %s test failed. Invalid output len\n", | 2679 | if (req->dst_len != c_size) { |
2673 | op); | 2680 | pr_err("alg: akcipher: %s test failed. Invalid output len\n", |
2674 | err = -EINVAL; | 2681 | op); |
2675 | goto free_all; | 2682 | err = -EINVAL; |
2676 | } | 2683 | goto free_all; |
2677 | /* verify that encrypted message is equal to expected */ | 2684 | } |
2678 | if (memcmp(c, outbuf_enc, c_size)) { | 2685 | /* verify that encrypted message is equal to expected */ |
2679 | pr_err("alg: akcipher: %s test failed. Invalid output\n", op); | 2686 | if (memcmp(c, outbuf_enc, c_size) != 0) { |
2680 | hexdump(outbuf_enc, c_size); | 2687 | pr_err("alg: akcipher: %s test failed. Invalid output\n", |
2681 | err = -EINVAL; | 2688 | op); |
2682 | goto free_all; | 2689 | hexdump(outbuf_enc, c_size); |
2690 | err = -EINVAL; | ||
2691 | goto free_all; | ||
2692 | } | ||
2683 | } | 2693 | } |
2684 | 2694 | ||
2685 | /* | 2695 | /* |
diff --git a/include/crypto/akcipher.h b/include/crypto/akcipher.h index 2d690494568c..2d26939fff51 100644 --- a/include/crypto/akcipher.h +++ b/include/crypto/akcipher.h | |||
@@ -19,14 +19,20 @@ | |||
19 | * | 19 | * |
20 | * @base: Common attributes for async crypto requests | 20 | * @base: Common attributes for async crypto requests |
21 | * @src: Source data | 21 | * @src: Source data |
22 | * @dst: Destination data | 22 | * For verify op this is signature + digest, in that case |
23 | * total size of @src is @src_len + @dst_len. | ||
24 | * @dst: Destination data (Should be NULL for verify op) | ||
23 | * @src_len: Size of the input buffer | 25 | * @src_len: Size of the input buffer |
24 | * @dst_len: Size of the output buffer. It needs to be at least | 26 | * For verify op it's size of signature part of @src, this part |
25 | * as big as the expected result depending on the operation | 27 | * is supposed to be operated by cipher. |
28 | * @dst_len: Size of @dst buffer (for all ops except verify). | ||
29 | * It needs to be at least as big as the expected result | ||
30 | * depending on the operation. | ||
26 | * After operation it will be updated with the actual size of the | 31 | * After operation it will be updated with the actual size of the |
27 | * result. | 32 | * result. |
28 | * In case of error where the dst sgl size was insufficient, | 33 | * In case of error where the dst sgl size was insufficient, |
29 | * it will be updated to the size required for the operation. | 34 | * it will be updated to the size required for the operation. |
35 | * For verify op this is size of digest part in @src. | ||
30 | * @__ctx: Start of private context data | 36 | * @__ctx: Start of private context data |
31 | */ | 37 | */ |
32 | struct akcipher_request { | 38 | struct akcipher_request { |
@@ -55,10 +61,9 @@ struct crypto_akcipher { | |||
55 | * algorithm. In case of error, where the dst_len was insufficient, | 61 | * algorithm. In case of error, where the dst_len was insufficient, |
56 | * the req->dst_len will be updated to the size required for the | 62 | * the req->dst_len will be updated to the size required for the |
57 | * operation | 63 | * operation |
58 | * @verify: Function performs a sign operation as defined by public key | 64 | * @verify: Function performs a complete verify operation as defined by |
59 | * algorithm. In case of error, where the dst_len was insufficient, | 65 | * public key algorithm, returning verification status. Requires |
60 | * the req->dst_len will be updated to the size required for the | 66 | * digest value as input parameter. |
61 | * operation | ||
62 | * @encrypt: Function performs an encrypt operation as defined by public key | 67 | * @encrypt: Function performs an encrypt operation as defined by public key |
63 | * algorithm. In case of error, where the dst_len was insufficient, | 68 | * algorithm. In case of error, where the dst_len was insufficient, |
64 | * the req->dst_len will be updated to the size required for the | 69 | * 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, | |||
238 | * | 243 | * |
239 | * @req: public key request | 244 | * @req: public key request |
240 | * @src: ptr to input scatter list | 245 | * @src: ptr to input scatter list |
241 | * @dst: ptr to output scatter list | 246 | * @dst: ptr to output scatter list or NULL for verify op |
242 | * @src_len: size of the src input scatter list to be processed | 247 | * @src_len: size of the src input scatter list to be processed |
243 | * @dst_len: size of the dst output scatter list | 248 | * @dst_len: size of the dst output scatter list or size of signature |
249 | * portion in @src for verify op | ||
244 | */ | 250 | */ |
245 | static inline void akcipher_request_set_crypt(struct akcipher_request *req, | 251 | static inline void akcipher_request_set_crypt(struct akcipher_request *req, |
246 | struct scatterlist *src, | 252 | struct scatterlist *src, |
@@ -343,14 +349,18 @@ static inline int crypto_akcipher_sign(struct akcipher_request *req) | |||
343 | } | 349 | } |
344 | 350 | ||
345 | /** | 351 | /** |
346 | * crypto_akcipher_verify() - Invoke public key verify operation | 352 | * crypto_akcipher_verify() - Invoke public key signature verification |
347 | * | 353 | * |
348 | * Function invokes the specific public key verify operation for a given | 354 | * Function invokes the specific public key signature verification operation |
349 | * public key algorithm | 355 | * for a given public key algorithm. |
350 | * | 356 | * |
351 | * @req: asymmetric key request | 357 | * @req: asymmetric key request |
352 | * | 358 | * |
353 | * Return: zero on success; error code in case of error | 359 | * Note: req->dst should be NULL, req->src should point to SG of size |
360 | * (req->src_size + req->dst_size), containing signature (of req->src_size | ||
361 | * length) with appended digest (of req->dst_size length). | ||
362 | * | ||
363 | * Return: zero on verification success; error code in case of error. | ||
354 | */ | 364 | */ |
355 | static inline int crypto_akcipher_verify(struct akcipher_request *req) | 365 | static inline int crypto_akcipher_verify(struct akcipher_request *req) |
356 | { | 366 | { |