diff options
author | Radu Alexe <radu.alexe@nxp.com> | 2017-05-03 13:17:13 (GMT) |
---|---|---|
committer | Xie Xiaobo <xiaobo.xie@nxp.com> | 2017-09-25 07:25:36 (GMT) |
commit | b5d8aefe5f22494dd4f910eb3bfe1791eb578731 (patch) | |
tree | 9c81880b9030d355ca141f3f0578dd8607ebac56 /crypto/testmgr.c | |
parent | 543dd4103bf940af2d88cf9fe2d7f173ea45615e (diff) | |
download | linux-b5d8aefe5f22494dd4f910eb3bfe1791eb578731.tar.xz |
crypto: add support for TLS 1.0 record encryption
This patch adds kernel support for encryption/decryption of TLS 1.0
records using block ciphers. Implementation is similar to authenc in the
sense that the base algorithms (AES, SHA1) are combined in a template to
produce TLS encapsulation frames. The composite algorithm will be called
"tls10(hmac(<digest>),cbc(<cipher>))". The cipher and hmac keys are
wrapped in the same format used by authenc.c.
Signed-off-by: Radu Alexe <radu.alexe@nxp.com>
Signed-off-by: Cristian Stoica <cristian.stoica@nxp.com>
Signed-off-by: Horia Geantă <horia.geanta@nxp.com>
Diffstat (limited to 'crypto/testmgr.c')
-rw-r--r-- | crypto/testmgr.c | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/crypto/testmgr.c b/crypto/testmgr.c index cd075c7..73d91fb 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -117,6 +117,13 @@ struct drbg_test_suite { unsigned int count; }; +struct tls_test_suite { + struct { + struct tls_testvec *vecs; + unsigned int count; + } enc, dec; +}; + struct akcipher_test_suite { const struct akcipher_testvec *vecs; unsigned int count; @@ -140,6 +147,7 @@ struct alg_test_desc { struct hash_test_suite hash; struct cprng_test_suite cprng; struct drbg_test_suite drbg; + struct tls_test_suite tls; struct akcipher_test_suite akcipher; struct kpp_test_suite kpp; } suite; @@ -991,6 +999,233 @@ static int test_aead(struct crypto_aead *tfm, int enc, return 0; } +static int __test_tls(struct crypto_aead *tfm, int enc, + struct tls_testvec *template, unsigned int tcount, + const bool diff_dst) +{ + const char *algo = crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm)); + unsigned int i, k, authsize; + char *q; + struct aead_request *req; + struct scatterlist *sg; + struct scatterlist *sgout; + const char *e, *d; + struct tcrypt_result result; + void *input; + void *output; + void *assoc; + char *iv; + char *key; + char *xbuf[XBUFSIZE]; + char *xoutbuf[XBUFSIZE]; + char *axbuf[XBUFSIZE]; + int ret = -ENOMEM; + + if (testmgr_alloc_buf(xbuf)) + goto out_noxbuf; + + if (diff_dst && testmgr_alloc_buf(xoutbuf)) + goto out_nooutbuf; + + if (testmgr_alloc_buf(axbuf)) + goto out_noaxbuf; + + iv = kzalloc(MAX_IVLEN, GFP_KERNEL); + if (!iv) + goto out_noiv; + + key = kzalloc(MAX_KEYLEN, GFP_KERNEL); + if (!key) + goto out_nokey; + + sg = kmalloc(sizeof(*sg) * 8 * (diff_dst ? 2 : 1), GFP_KERNEL); + if (!sg) + goto out_nosg; + + sgout = sg + 8; + + d = diff_dst ? "-ddst" : ""; + e = enc ? "encryption" : "decryption"; + + init_completion(&result.completion); + + req = aead_request_alloc(tfm, GFP_KERNEL); + if (!req) { + pr_err("alg: tls%s: Failed to allocate request for %s\n", + d, algo); + goto out; + } + + aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + tcrypt_complete, &result); + + for (i = 0; i < tcount; i++) { + input = xbuf[0]; + assoc = axbuf[0]; + + ret = -EINVAL; + if (WARN_ON(template[i].ilen > PAGE_SIZE || + template[i].alen > PAGE_SIZE)) + goto out; + + memcpy(assoc, template[i].assoc, template[i].alen); + memcpy(input, template[i].input, template[i].ilen); + + if (template[i].iv) + memcpy(iv, template[i].iv, MAX_IVLEN); + else + memset(iv, 0, MAX_IVLEN); + + crypto_aead_clear_flags(tfm, ~0); + + if (template[i].klen > MAX_KEYLEN) { + pr_err("alg: aead%s: setkey failed on test %d for %s: key size %d > %d\n", + d, i, algo, template[i].klen, MAX_KEYLEN); + ret = -EINVAL; + goto out; + } + memcpy(key, template[i].key, template[i].klen); + + ret = crypto_aead_setkey(tfm, key, template[i].klen); + if (!ret == template[i].fail) { + pr_err("alg: tls%s: setkey failed on test %d for %s: flags=%x\n", + d, i, algo, crypto_aead_get_flags(tfm)); + goto out; + } else if (ret) + continue; + + authsize = 20; + ret = crypto_aead_setauthsize(tfm, authsize); + if (ret) { + pr_err("alg: aead%s: Failed to set authsize to %u on test %d for %s\n", + d, authsize, i, algo); + goto out; + } + + k = !!template[i].alen; + sg_init_table(sg, k + 1); + sg_set_buf(&sg[0], assoc, template[i].alen); + sg_set_buf(&sg[k], input, (enc ? template[i].rlen : + template[i].ilen)); + output = input; + + if (diff_dst) { + sg_init_table(sgout, k + 1); + sg_set_buf(&sgout[0], assoc, template[i].alen); + + output = xoutbuf[0]; + sg_set_buf(&sgout[k], output, + (enc ? template[i].rlen : template[i].ilen)); + } + + aead_request_set_crypt(req, sg, (diff_dst) ? sgout : sg, + template[i].ilen, iv); + + aead_request_set_ad(req, template[i].alen); + + ret = enc ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req); + + switch (ret) { + case 0: + if (template[i].novrfy) { + /* verification was supposed to fail */ + pr_err("alg: tls%s: %s failed on test %d for %s: ret was 0, expected -EBADMSG\n", + d, e, i, algo); + /* so really, we got a bad message */ + ret = -EBADMSG; + goto out; + } + break; + case -EINPROGRESS: + case -EBUSY: + wait_for_completion(&result.completion); + reinit_completion(&result.completion); + ret = result.err; + if (!ret) + break; + case -EBADMSG: + /* verification failure was expected */ + if (template[i].novrfy) + continue; + /* fall through */ + default: + pr_err("alg: tls%s: %s failed on test %d for %s: ret=%d\n", + d, e, i, algo, -ret); + goto out; + } + + q = output; + if (memcmp(q, template[i].result, template[i].rlen)) { + pr_err("alg: tls%s: Test %d failed on %s for %s\n", + d, i, e, algo); + hexdump(q, template[i].rlen); + pr_err("should be:\n"); + hexdump(template[i].result, template[i].rlen); + ret = -EINVAL; + goto out; + } + } + +out: + aead_request_free(req); + + kfree(sg); +out_nosg: + kfree(key); +out_nokey: + kfree(iv); +out_noiv: + testmgr_free_buf(axbuf); +out_noaxbuf: + if (diff_dst) + testmgr_free_buf(xoutbuf); +out_nooutbuf: + testmgr_free_buf(xbuf); +out_noxbuf: + return ret; +} + +static int test_tls(struct crypto_aead *tfm, int enc, + struct tls_testvec *template, unsigned int tcount) +{ + int ret; + /* test 'dst == src' case */ + ret = __test_tls(tfm, enc, template, tcount, false); + if (ret) + return ret; + /* test 'dst != src' case */ + return __test_tls(tfm, enc, template, tcount, true); +} + +static int alg_test_tls(const struct alg_test_desc *desc, const char *driver, + u32 type, u32 mask) +{ + struct crypto_aead *tfm; + int err = 0; + + tfm = crypto_alloc_aead(driver, type, mask); + if (IS_ERR(tfm)) { + pr_err("alg: aead: Failed to load transform for %s: %ld\n", + driver, PTR_ERR(tfm)); + return PTR_ERR(tfm); + } + + if (desc->suite.tls.enc.vecs) { + err = test_tls(tfm, ENCRYPT, desc->suite.tls.enc.vecs, + desc->suite.tls.enc.count); + if (err) + goto out; + } + + if (!err && desc->suite.tls.dec.vecs) + err = test_tls(tfm, DECRYPT, desc->suite.tls.dec.vecs, + desc->suite.tls.dec.count); + +out: + crypto_free_aead(tfm); + return err; +} + static int test_cipher(struct crypto_cipher *tfm, int enc, const struct cipher_testvec *template, unsigned int tcount) @@ -3414,6 +3649,15 @@ static const struct alg_test_desc alg_test_descs[] = { .hash = __VECS(tgr192_tv_template) } }, { + .alg = "tls10(hmac(sha1),cbc(aes))", + .test = alg_test_tls, + .suite = { + .tls = { + .enc = __VECS(tls_enc_tv_template), + .dec = __VECS(tls_dec_tv_template) + } + } + }, { .alg = "vmac(aes)", .test = alg_test_hash, .suite = { |