SUNRPC: Add encryption self-tests
authorChuck Lever <chuck.lever@oracle.com>
Sun, 15 Jan 2023 17:24:38 +0000 (12:24 -0500)
committerChuck Lever <chuck.lever@oracle.com>
Mon, 20 Feb 2023 14:20:51 +0000 (09:20 -0500)
With the KUnit infrastructure recently added, we are free to define
other unit tests particular to our implementation. As an example,
I've added a self-test that encrypts then decrypts a string, and
checks the result.

Tested-by: Scott Mayhew <smayhew@redhat.com>
Reviewed-by: Simo Sorce <simo@redhat.com>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
net/sunrpc/auth_gss/gss_krb5_crypto.c
net/sunrpc/auth_gss/gss_krb5_internal.h
net/sunrpc/auth_gss/gss_krb5_test.c

index d0879a4d312242462ec94cb47b55b8317acee502..6c7c52eeed4f85773c71fea22879d04b14a9f665 100644 (file)
@@ -713,10 +713,21 @@ int krb5_cbc_cts_encrypt(struct crypto_sync_skcipher *cts_tfm,
 }
 EXPORT_SYMBOL_IF_KUNIT(krb5_cbc_cts_encrypt);
 
-static int
-krb5_cbc_cts_decrypt(struct crypto_sync_skcipher *cts_tfm,
-                    struct crypto_sync_skcipher *cbc_tfm,
-                    u32 offset, struct xdr_buf *buf)
+/**
+ * krb5_cbc_cts_decrypt - decrypt in CBC mode with CTS
+ * @cts_tfm: CBC cipher with CTS
+ * @cbc_tfm: base CBC cipher
+ * @offset: starting byte offset for plaintext
+ * @buf: OUT: output buffer
+ *
+ * Return values:
+ *   %0: decryption successful
+ *   negative errno: decryption could not be completed
+ */
+VISIBLE_IF_KUNIT
+int krb5_cbc_cts_decrypt(struct crypto_sync_skcipher *cts_tfm,
+                        struct crypto_sync_skcipher *cbc_tfm,
+                        u32 offset, struct xdr_buf *buf)
 {
        u32 blocksize, nblocks, cbcbytes;
        struct decryptor_desc desc;
@@ -752,6 +763,7 @@ krb5_cbc_cts_decrypt(struct crypto_sync_skcipher *cts_tfm,
        /* Remaining plaintext is handled with CBC-CTS. */
        return gss_krb5_cts_crypt(cts_tfm, buf, cbcbytes, desc.iv, NULL, 0);
 }
+EXPORT_SYMBOL_IF_KUNIT(krb5_cbc_cts_decrypt);
 
 u32
 gss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset,
index c907eda2ad72872652f790352d835c6382a72bc6..b673e2626acb298253d10c6283591a3a8aae1ccb 100644 (file)
@@ -221,6 +221,9 @@ int krb5_cbc_cts_encrypt(struct crypto_sync_skcipher *cts_tfm,
                         struct crypto_sync_skcipher *cbc_tfm, u32 offset,
                         struct xdr_buf *buf, struct page **pages,
                         u8 *iv, unsigned int ivsize);
+int krb5_cbc_cts_decrypt(struct crypto_sync_skcipher *cts_tfm,
+                        struct crypto_sync_skcipher *cbc_tfm,
+                        u32 offset, struct xdr_buf *buf);
 u32 krb5_etm_checksum(struct crypto_sync_skcipher *cipher,
                      struct crypto_ahash *tfm, const struct xdr_buf *body,
                      int body_offset, struct xdr_netobj *cksumout);
index fe3e4b81221aecae46353dc9f1c244b1ec9c24da..c287ce15c419f432d97609158d3f2ec49a7709a2 100644 (file)
@@ -1909,10 +1909,132 @@ static struct kunit_suite rfc8009_suite = {
        .test_cases             = rfc8009_test_cases,
 };
 
+/*
+ * Encryption self-tests
+ */
+
+DEFINE_STR_XDR_NETOBJ(encrypt_selftest_plaintext,
+                     "This is the plaintext for the encryption self-test.");
+
+static const struct gss_krb5_test_param encrypt_selftest_params[] = {
+       {
+               .desc                   = "aes128-cts-hmac-sha1-96 encryption self-test",
+               .enctype                = ENCTYPE_AES128_CTS_HMAC_SHA1_96,
+               .Ke                     = &rfc3962_encryption_key,
+               .plaintext              = &encrypt_selftest_plaintext,
+       },
+       {
+               .desc                   = "aes256-cts-hmac-sha1-96 encryption self-test",
+               .enctype                = ENCTYPE_AES256_CTS_HMAC_SHA1_96,
+               .Ke                     = &rfc3962_encryption_key,
+               .plaintext              = &encrypt_selftest_plaintext,
+       },
+       {
+               .desc                   = "camellia128-cts-cmac encryption self-test",
+               .enctype                = ENCTYPE_CAMELLIA128_CTS_CMAC,
+               .Ke                     = &camellia128_cts_cmac_Ke,
+               .plaintext              = &encrypt_selftest_plaintext,
+       },
+       {
+               .desc                   = "camellia256-cts-cmac encryption self-test",
+               .enctype                = ENCTYPE_CAMELLIA256_CTS_CMAC,
+               .Ke                     = &camellia256_cts_cmac_Ke,
+               .plaintext              = &encrypt_selftest_plaintext,
+       },
+       {
+               .desc                   = "aes128-cts-hmac-sha256-128 encryption self-test",
+               .enctype                = ENCTYPE_AES128_CTS_HMAC_SHA256_128,
+               .Ke                     = &aes128_cts_hmac_sha256_128_Ke,
+               .plaintext              = &encrypt_selftest_plaintext,
+       },
+       {
+               .desc                   = "aes256-cts-hmac-sha384-192 encryption self-test",
+               .enctype                = ENCTYPE_AES256_CTS_HMAC_SHA384_192,
+               .Ke                     = &aes256_cts_hmac_sha384_192_Ke,
+               .plaintext              = &encrypt_selftest_plaintext,
+       },
+};
+
+/* Creates the function encrypt_selftest_gen_params */
+KUNIT_ARRAY_PARAM(encrypt_selftest, encrypt_selftest_params,
+                 gss_krb5_get_desc);
+
+/*
+ * Encrypt and decrypt plaintext, and ensure the input plaintext
+ * matches the output plaintext. A confounder is not added in this
+ * case.
+ */
+static void encrypt_selftest_case(struct kunit *test)
+{
+       const struct gss_krb5_test_param *param = test->param_value;
+       struct crypto_sync_skcipher *cts_tfm, *cbc_tfm;
+       const struct gss_krb5_enctype *gk5e;
+       struct xdr_buf buf;
+       void *text;
+       int err;
+
+       /* Arrange */
+       gk5e = gss_krb5_lookup_enctype(param->enctype);
+       KUNIT_ASSERT_NOT_NULL(test, gk5e);
+
+       cbc_tfm = crypto_alloc_sync_skcipher(gk5e->aux_cipher, 0, 0);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cbc_tfm);
+       err = crypto_sync_skcipher_setkey(cbc_tfm, param->Ke->data, param->Ke->len);
+       KUNIT_ASSERT_EQ(test, err, 0);
+
+       cts_tfm = crypto_alloc_sync_skcipher(gk5e->encrypt_name, 0, 0);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cts_tfm);
+       err = crypto_sync_skcipher_setkey(cts_tfm, param->Ke->data, param->Ke->len);
+       KUNIT_ASSERT_EQ(test, err, 0);
+
+       text = kunit_kzalloc(test, roundup(param->plaintext->len,
+                                          crypto_sync_skcipher_blocksize(cbc_tfm)),
+                            GFP_KERNEL);
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, text);
+
+       memcpy(text, param->plaintext->data, param->plaintext->len);
+       memset(&buf, 0, sizeof(buf));
+       buf.head[0].iov_base = text;
+       buf.head[0].iov_len = param->plaintext->len;
+       buf.len = buf.head[0].iov_len;
+
+       /* Act */
+       err = krb5_cbc_cts_encrypt(cts_tfm, cbc_tfm, 0, &buf, NULL, NULL, 0);
+       KUNIT_ASSERT_EQ(test, err, 0);
+       err = krb5_cbc_cts_decrypt(cts_tfm, cbc_tfm, 0, &buf);
+       KUNIT_ASSERT_EQ(test, err, 0);
+
+       /* Assert */
+       KUNIT_EXPECT_EQ_MSG(test,
+                           param->plaintext->len, buf.len,
+                           "length mismatch");
+       KUNIT_EXPECT_EQ_MSG(test,
+                           memcmp(param->plaintext->data,
+                                  buf.head[0].iov_base, buf.len), 0,
+                           "plaintext mismatch");
+
+       crypto_free_sync_skcipher(cts_tfm);
+       crypto_free_sync_skcipher(cbc_tfm);
+}
+
+static struct kunit_case encryption_test_cases[] = {
+       {
+               .name                   = "Encryption self-tests",
+               .run_case               = encrypt_selftest_case,
+               .generate_params        = encrypt_selftest_gen_params,
+       },
+};
+
+static struct kunit_suite encryption_test_suite = {
+       .name                   = "Encryption test suite",
+       .test_cases             = encryption_test_cases,
+};
+
 kunit_test_suites(&rfc3961_suite,
                  &rfc3962_suite,
                  &rfc6803_suite,
-                 &rfc8009_suite);
+                 &rfc8009_suite,
+                 &encryption_test_suite);
 
 MODULE_DESCRIPTION("Test RPCSEC GSS Kerberos 5 functions");
 MODULE_LICENSE("GPL");