diff options
Diffstat (limited to 'crypto/testmgr.c')
-rw-r--r-- | crypto/testmgr.c | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 7795550..6221c54 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -108,6 +108,13 @@ struct cprng_test_suite { unsigned int count; }; +struct tls_test_suite { + struct { + struct tls_testvec *vecs; + unsigned int count; + } enc, dec; +}; + struct alg_test_desc { const char *alg; int (*test)(const struct alg_test_desc *desc, const char *driver, @@ -121,6 +128,7 @@ struct alg_test_desc { struct pcomp_test_suite pcomp; struct hash_test_suite hash; struct cprng_test_suite cprng; + struct tls_test_suite tls; } suite; }; @@ -803,6 +811,218 @@ 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, rlen; + int ret = -ENOMEM; + char *q; + char *key; + struct aead_request *req; + struct scatterlist *sg; + struct scatterlist *asg; + struct scatterlist *sgout; + const char *e, *d; + struct tcrypt_result result; + void *input; + void *output; + void *assoc; + char iv[MAX_IVLEN]; + char *xbuf[XBUFSIZE]; + char *xoutbuf[XBUFSIZE]; + char *axbuf[XBUFSIZE]; + + if (testmgr_alloc_buf(xbuf)) + goto out_noxbuf; + if (testmgr_alloc_buf(axbuf)) + goto out_noaxbuf; + + if (diff_dst && testmgr_alloc_buf(xoutbuf)) + goto out_nooutbuf; + + sg = kmalloc(sizeof(*sg) * 8 * (diff_dst ? 3 : 2), GFP_KERNEL); + if (!sg) + goto out_nosg; + asg = &sg[8]; + sgout = &asg[8]; + + if (diff_dst) + d = "-ddst"; + else + d = ""; + + if (enc == ENCRYPT) + e = "encryption"; + else + e = "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(input, template[i].input, template[i].ilen); + memcpy(assoc, template[i].assoc, template[i].alen); + if (template[i].iv) + memcpy(iv, template[i].iv, MAX_IVLEN); + else + memset(iv, 0, MAX_IVLEN); + + crypto_aead_clear_flags(tfm, ~0); + key = template[i].key; + + 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; + } + if (ret) + continue; + + output = diff_dst ? xoutbuf[0] : input; + + /* Allocate enough space in the input and output scatterlists. + * They must accomodate the result for in-place encryption and + * different-place decryption + */ + rlen = max(template[i].ilen, template[i].rlen); + if (diff_dst) { + output = xoutbuf[0]; + sg_init_one(&sg[0], input, template[i].ilen); + sg_init_one(&sgout[0], output, rlen); + } else { + output = input; + sg_init_one(&sg[0], input, rlen); + } + + sg_init_one(&asg[0], assoc, template[i].alen); + + aead_request_set_assoc(req, asg, template[i].alen); + aead_request_set_crypt(req, sg, (diff_dst) ? sgout : sg, + template[i].ilen, iv); + + 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: + /* The result is not ready yet. We wait for it and then + * check if the request succeeded or not + */ + ret = wait_for_completion_interruptible( + &result.completion); + if (!ret && !result.err) { + reinit_completion(&result.completion); + break; + } else { + ret = result.err; + } + /* fall through */ + 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: + if (diff_dst) + testmgr_free_buf(xoutbuf); +out_nooutbuf: + testmgr_free_buf(axbuf); +out_noaxbuf: + 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, struct cipher_testvec *template, unsigned int tcount) { @@ -3000,6 +3220,21 @@ static const struct alg_test_desc alg_test_descs[] = { } } }, { + .alg = "tls10(hmac(sha1),cbc(aes))", + .test = alg_test_tls, + .suite = { + .tls = { + .enc = { + .vecs = tls_enc_tv_template, + .count = TLS_ENC_TEST_VECTORS + }, + .dec = { + .vecs = tls_dec_tv_template, + .count = TLS_DEC_TEST_VECTORS + } + } + } + }, { .alg = "vmac(aes)", .test = alg_test_hash, .suite = { |