Am Freitag, 20. Januar 2017, 17:06:00 CET schrieb Nitin Kumbhar: Hi Nitin, > Update crypto test manager to include NIST ECDSA > test vectors and various ECDSA tests. These include > tests for ECDSA signing, ECDSA sign-verification, > ECDSA signing and verifying generated signatures and > invalidation of incorrect signatures. > > Signed-off-by: Nitin Kumbhar <nkumbhar@xxxxxxxxxx> > --- > crypto/testmgr.c | 452 > +++++++++++++++++++++++++++++++++++++++++++++++++++++- crypto/testmgr.h | > 140 +++++++++++++++++ > 2 files changed, 589 insertions(+), 3 deletions(-) > > diff --git a/crypto/testmgr.c b/crypto/testmgr.c > index 98eb09782db8..a1db28cbc32d 100644 > --- a/crypto/testmgr.c > +++ b/crypto/testmgr.c > @@ -5,6 +5,7 @@ > * Copyright (c) 2002 Jean-Francois Dive <jef@xxxxxxxxxxx> > * Copyright (c) 2007 Nokia Siemens Networks > * Copyright (c) 2008 Herbert Xu <herbert@xxxxxxxxxxxxxxxxxxx> > + * Copyright (c) 2017 NVIDIA Corporation > * > * Updated RFC4106 AES-GCM testing. > * Authors: Aidan O'Mahony (aidan.o.mahony@xxxxxxxxx) > @@ -2085,6 +2086,436 @@ static int alg_test_kpp(const struct alg_test_desc > *desc, const char *driver, return err; > } > > +static int do_test_ecdsa_verify(struct crypto_akcipher *tfm, > + struct akcipher_testvec *vec) > +{ > + struct akcipher_request *req = NULL; > + u8 *r_str = NULL, *s_str = NULL; > + u8 *m_str = NULL; > + struct scatterlist src_tab[3], dst; > + struct tcrypt_result result; > + unsigned int outbuf_maxlen; > + u8 *outbuf = NULL; > + unsigned int nbytes; > + int err; > + > + /* Alloc akcipher request */ > + req = akcipher_request_alloc(tfm, GFP_KERNEL); > + if (!req) > + return -ENOMEM; > + > + /* Set private key */ > + err = crypto_akcipher_set_pub_key(tfm, vec->key, vec->key_len); > + if (err) > + goto error; > + > + /* > + * vec->c always contains k, R and S in that order. All are > + * of same size and are equal to n i.e. the order of > + * an elliptic curve. > + */ > + nbytes = vec->c_size / 3; > + > + r_str = kzalloc(nbytes, GFP_KERNEL); > + s_str = kzalloc(nbytes, GFP_KERNEL); > + m_str = kzalloc(vec->m_size, GFP_KERNEL); > + if (!r_str || !s_str || !m_str) { > + err = -ENOMEM; > + goto error; > + } > + memcpy(r_str, (u8 *)vec->c + nbytes, nbytes); > + memcpy(s_str, (u8 *)vec->c + 2 * nbytes, nbytes); > + memcpy(m_str, vec->m, vec->m_size); > + > + outbuf_maxlen = crypto_akcipher_maxsize(tfm); > + if (outbuf_maxlen < 0) { > + err = outbuf_maxlen; > + goto error; > + } > + outbuf = kzalloc(outbuf_maxlen, GFP_KERNEL); > + if (!outbuf) { > + err = -ENOMEM; > + goto error; > + } > + > + /* Set src and dst buffers */ > + sg_init_table(src_tab, 3); > + sg_set_buf(&src_tab[0], m_str, vec->m_size); > + sg_set_buf(&src_tab[1], r_str, nbytes); > + sg_set_buf(&src_tab[2], s_str, nbytes); > + sg_init_one(&dst, outbuf, outbuf_maxlen); > + > + akcipher_request_set_crypt(req, src_tab, &dst, > + vec->m_size + 2 * nbytes, outbuf_maxlen); > + > + /* Set up result callback */ > + init_completion(&result.completion); > + akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, > + tcrypt_complete, &result); > + > + /* Run ecdsa verify operation on sig (r,s) */ > + err = wait_async_op(&result, crypto_akcipher_verify(req)); > + if (err) { > + pr_err("alg: ecdsa: verify(rs) test failed. err %d\n", err); > + goto error; > + } > +error: > + akcipher_request_free(req); > + kfree(r_str); > + kfree(s_str); > + kfree(m_str); > + kfree(outbuf); > + return err; > +} > + > +static int do_test_ecdsa_invalid_verify(struct crypto_akcipher *tfm, > + struct akcipher_testvec *vec) > +{ > + struct akcipher_request *req = NULL; > + u8 *r_str = NULL, *s_str = NULL; > + u8 *m_str = NULL; > + struct scatterlist src_tab[3], dst; > + struct tcrypt_result result; > + unsigned int outbuf_maxlen; > + u8 *outbuf = NULL; > + unsigned int nbytes; > + int err; > + > + /* Alloc akcipher request */ > + req = akcipher_request_alloc(tfm, GFP_KERNEL); > + if (!req) > + return -ENOMEM; > + > + /* Set private key */ > + err = crypto_akcipher_set_pub_key(tfm, vec->key, vec->key_len); > + if (err) > + goto error; > + > + /* > + * vec->c always contains k, R and S in that order. All are > + * of same size and are equal to n i.e. the order of > + * an elliptic curve. > + */ > + nbytes = vec->c_size / 3; > + > + r_str = kzalloc(nbytes, GFP_KERNEL); > + s_str = kzalloc(nbytes, GFP_KERNEL); > + m_str = kzalloc(vec->m_size, GFP_KERNEL); > + if (!r_str || !s_str || !m_str) { > + err = -ENOMEM; > + goto error; > + } > + memcpy(r_str, (u8 *)vec->c + 1 * nbytes, nbytes); > + memcpy(s_str, (u8 *)vec->c + 2 * nbytes, nbytes); > + memcpy(m_str, vec->m, vec->m_size); > + > + outbuf_maxlen = crypto_akcipher_maxsize(tfm); > + if (outbuf_maxlen < 0) { > + err = outbuf_maxlen; > + goto error; > + } > + outbuf = kzalloc(outbuf_maxlen, GFP_KERNEL); > + if (!outbuf) { > + err = -ENOMEM; > + goto error; > + } > + > + /* Set src and dst buffers */ > + sg_init_table(src_tab, 3); > + /* Intentionally set m_size to 8 to have invalid hash */ > + sg_set_buf(&src_tab[0], m_str, 8); > + sg_set_buf(&src_tab[1], r_str, nbytes); > + sg_set_buf(&src_tab[2], s_str, nbytes); > + sg_init_one(&dst, outbuf, outbuf_maxlen); > + > + akcipher_request_set_crypt(req, src_tab, &dst, > + vec->m_size + 2 * nbytes, outbuf_maxlen); > + > + /* Set up result callback */ > + init_completion(&result.completion); > + akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, > + tcrypt_complete, &result); > + > + /* Run ecdsa verify operation on sig (r,s) */ > + err = wait_async_op(&result, crypto_akcipher_verify(req)); > + if (err != -EBADMSG) { > + pr_err("alg: ecdsa: invalid verify test failed. err %d\n", err); > + goto error; > + } > + err = 0; > +error: > + akcipher_request_free(req); > + kfree(r_str); > + kfree(s_str); > + kfree(m_str); > + kfree(outbuf); > + return err; > +} There seems to be a lot of code duplication between do_test_ecdsa_invalid_verify and do_test_ecdsa_verify -- can this be eliminated? > + > +static int do_test_ecdsa_sign_verify(struct crypto_akcipher *tfm, > + struct akcipher_testvec *vec) > +{ > + struct akcipher_request *req = NULL; > + u8 *r_str = NULL, *s_str = NULL; > + u8 *m_str = NULL; > + struct scatterlist src_tab[3]; > + struct scatterlist src, dst; > + struct tcrypt_result result; > + unsigned int outbuf_maxlen; > + void *outbuf = NULL; > + unsigned int nbytes; > + int err; > + > + /* Alloc akcipher request */ > + req = akcipher_request_alloc(tfm, GFP_KERNEL); > + if (!req) > + return -ENOMEM; > + > + /* Set private key */ > + err = crypto_akcipher_set_priv_key(tfm, vec->key, vec->key_len); > + if (err) > + goto error; > + > + /* Set private key */ > + err = crypto_akcipher_set_pub_key(tfm, vec->key, vec->key_len); > + if (err) > + goto error; > + > + /* > + * vec->c always contains k, R and S in that order. All are > + * of same size and are equal to n i.e. the order of > + * an elliptic curve. > + */ > + nbytes = vec->c_size / 3; > + > + m_str = kzalloc(vec->m_size, GFP_KERNEL); > + if (!m_str) { > + err = -ENOMEM; > + goto error; > + } > + memcpy(m_str, vec->m, vec->m_size); > + > + outbuf_maxlen = crypto_akcipher_maxsize(tfm); > + if (outbuf_maxlen < 0) { > + err = outbuf_maxlen; > + goto error; > + } > + outbuf = kzalloc(outbuf_maxlen, GFP_KERNEL); > + if (!outbuf) { > + err = -ENOMEM; > + goto error; > + } > + > + sg_init_one(&src, m_str, vec->m_size); > + sg_init_one(&dst, outbuf, outbuf_maxlen); > + > + akcipher_request_set_crypt(req, &src, &dst, > + vec->m_size, outbuf_maxlen); > + > + /* Set up result callback */ > + init_completion(&result.completion); > + akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, > + tcrypt_complete, &result); > + > + /* Run ecdsa sign operation on message digest */ > + err = wait_async_op(&result, crypto_akcipher_sign(req)); > + if (err) { > + pr_err("alg: ecdsa: sign test failed. err %d\n", err); > + goto error; > + } > + > + /* verify that signature (r,s) is valid */ > + if (req->dst_len != 2 * nbytes) { > + pr_err("alg: ecdsa: sign test failed. Invalid sig len\n"); > + err = -EINVAL; > + goto error; > + } > + > + /* output contains r and s */ > + r_str = outbuf; > + s_str = (u8 *)outbuf + nbytes; > + > + /* Set src and dst buffers */ > + sg_init_table(src_tab, 3); > + sg_set_buf(&src_tab[0], m_str, vec->m_size); > + sg_set_buf(&src_tab[1], r_str, nbytes); > + sg_set_buf(&src_tab[2], s_str, nbytes); > + sg_init_one(&dst, outbuf, outbuf_maxlen); > + > + akcipher_request_set_crypt(req, src_tab, &dst, > + vec->m_size + 2 * nbytes, outbuf_maxlen); > + > + /* Set up result callback */ > + init_completion(&result.completion); > + akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, > + tcrypt_complete, &result); > + > + /* Run ecdsa verify operation on sig (r,s) */ > + err = wait_async_op(&result, crypto_akcipher_verify(req)); > + if (err) { > + pr_err("alg: ecdsa: verify test failed. err %d\n", err); > + goto error; > + } > +error: > + akcipher_request_free(req); > + kfree(m_str); > + kfree(outbuf); > + return err; > +} > + > +static int do_test_ecdsa_sign(struct crypto_akcipher *tfm, > + struct akcipher_testvec *vec) > +{ > + struct akcipher_request *req = NULL; > + u8 *r_str = NULL, *s_str = NULL; > + u8 *k_str = NULL, *m_str = NULL; > + struct scatterlist src, dst; > + struct tcrypt_result result; > + unsigned int outbuf_maxlen; > + void *outbuf = NULL; > + unsigned int nbytes; > + int err; > + > + /* Alloc akcipher request */ > + req = akcipher_request_alloc(tfm, GFP_KERNEL); > + if (!req) > + return -ENOMEM; > + > + /* Set private key */ > + err = crypto_akcipher_set_priv_key(tfm, vec->key, vec->key_len); > + if (err) > + goto error; > + > + /* > + * vec->c always contains k, R and S in that order. All are > + * of same size and are equal to n i.e. the order of > + * an elliptic curve. > + */ > + nbytes = vec->c_size / 3; > + > + k_str = kzalloc(nbytes, GFP_KERNEL); > + r_str = kzalloc(nbytes, GFP_KERNEL); > + s_str = kzalloc(nbytes, GFP_KERNEL); > + m_str = kzalloc(vec->m_size, GFP_KERNEL); > + if (!k_str || !r_str || !s_str || !m_str) { > + err = -ENOMEM; > + goto error; > + } > + memcpy(k_str, (u8 *)vec->c + 0 * nbytes, nbytes); > + memcpy(r_str, (u8 *)vec->c + 1 * nbytes, nbytes); > + memcpy(s_str, (u8 *)vec->c + 2 * nbytes, nbytes); > + memcpy(m_str, vec->m, vec->m_size); > + > + outbuf_maxlen = crypto_akcipher_maxsize(tfm); > + if (outbuf_maxlen < 0) { > + err = outbuf_maxlen; > + goto error; > + } > + outbuf = kzalloc(outbuf_maxlen, GFP_KERNEL); > + if (!outbuf) { > + err = -ENOMEM; > + goto error; > + } > + > + /* Set src and dst buffers */ > + sg_init_one(&src, m_str, vec->m_size); > + sg_init_one(&dst, outbuf, outbuf_maxlen); > + > + akcipher_request_set_crypt(req, &src, &dst, > + vec->m_size, outbuf_maxlen); > + > + /* Set up result callback */ > + init_completion(&result.completion); > + akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, > + tcrypt_complete, &result); > + > + /* Set K in request for signing */ > + req->info = k_str; > + > + /* Run ecdsa sign operation on message digest */ > + err = wait_async_op(&result, crypto_akcipher_sign(req)); > + if (err) { > + pr_err("alg: ecdsa: sign(k) test failed. err %d\n", err); > + goto error; > + } > + > + /* verify that signature (r,s) is valid */ > + if (req->dst_len != 2 * nbytes) { > + pr_err("alg: ecdsa: sign(k) test failed. Invalid sig len\n"); > + err = -EINVAL; > + goto error; > + } > + > + if (memcmp(r_str, sg_virt(req->dst), nbytes)) { > + pr_err("alg: ecdsa: sign(k) test failed. Invalid sig(r)\n"); > + err = -EINVAL; > + goto error; > + } > + > + if (memcmp(s_str, (u8 *)sg_virt(req->dst) + nbytes, nbytes)) { > + pr_err("alg: ecdsa: sign(k) test failed. Invalid sig(s)\n"); > + err = -EINVAL; > + goto error; > + } > +error: > + akcipher_request_free(req); > + kfree(k_str); > + kfree(r_str); > + kfree(s_str); > + kfree(m_str); > + kfree(outbuf); > + return err; > +} Same here -- there seem to be a lot of code duplication -- can this be reduced? > + > +static int test_ecdsa_akcipher(struct crypto_akcipher *tfm, const char > *alg, + struct akcipher_testvec *vecs, unsigned int tcount) > +{ > + int i, err = 0; > + > + for (i = 0; i < tcount; i++) { > + err = do_test_ecdsa_verify(tfm, &vecs[i]); > + if (!err) > + continue; > + > + pr_err("ecdsa: verify failed on vec %d, err=%d\n", > + i + 1, err); All of these pr_err logs here and below should be removed as these errors seem to be already logged. > + goto exit; > + } > + > + for (i = 0; i < tcount; i++) { > + err = do_test_ecdsa_invalid_verify(tfm, &vecs[i]); > + if (!err) > + continue; > + > + pr_err("ecdsa: verify(invl) failed on vec %d, err=%d\n", > + i + 1, err); > + goto exit; > + } > + > + for (i = 0; i < tcount; i++) { > + err = do_test_ecdsa_sign_verify(tfm, &vecs[i]); > + if (!err) > + continue; > + > + pr_err("ecdsa: sign/verify failed on vec %d, err=%d\n", > + i + 1, err); > + goto exit; > + } > + > + for (i = 0; i < tcount; i++) { > + err = do_test_ecdsa_sign(tfm, &vecs[i]); > + if (!err) > + continue; > + > + pr_err("ecdsa: sign failed on vec %d, err=%d\n", > + i + 1, err); > + goto exit; > + } > + exit: > + pr_info("test_ecdsa: %s\n", err ? "FAILED" : "PASSED"); This log message should go away. > + return err; > +} > + > static int test_akcipher_one(struct crypto_akcipher *tfm, > struct akcipher_testvec *vecs) > { > @@ -2236,9 +2667,17 @@ static int alg_test_akcipher(const struct > alg_test_desc *desc, driver, PTR_ERR(tfm)); > return PTR_ERR(tfm); > } > - if (desc->suite.akcipher.vecs) > - err = test_akcipher(tfm, desc->alg, desc->suite.akcipher.vecs, > - desc->suite.akcipher.count); > + > + if (desc->suite.akcipher.vecs) { > + if (strncmp(desc->alg, "ecdsa", 5) == 0) > + err = test_ecdsa_akcipher(tfm, desc->alg, > + desc->suite.akcipher.vecs, > + desc->suite.akcipher.count); > + else > + err = test_akcipher(tfm, desc->alg, > + desc->suite.akcipher.vecs, > + desc->suite.akcipher.count); > + } > > crypto_free_akcipher(tfm); > return err; > @@ -2982,6 +3421,13 @@ static int alg_test_null(const struct alg_test_desc > *desc, .kpp = __VECS(ecdh_tv_template) > } > }, { > + .alg = "ecdsa", > + .test = alg_test_akcipher, > + .fips_allowed = 1, > + .suite = { > + .akcipher = __VECS(ecdsa_tv_template) > + } > + }, { Ciao Stephan -- To unsubscribe from this list: send the line "unsubscribe linux-crypto" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html