Re: [PATCH v7 4/6] Add SPAcc aead support
From: Dan Carpenter <hidden>
Date: 2024-08-15 06:06:36
On Mon, Jul 29, 2024 at 09:43:48AM +0530, Pavitrakumar M wrote:
+static int spacc_aead_setkey(struct crypto_aead *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct spacc_crypto_ctx *ctx = crypto_aead_ctx(tfm);
+ const struct spacc_alg *salg = spacc_tfm_aead(&tfm->base);
+ struct spacc_priv *priv;
+ struct rtattr *rta = (void *)key;
+ struct crypto_authenc_key_param *param;
+ unsigned int authkeylen, enckeylen;
+ const unsigned char *authkey, *enckey;
+ unsigned char xcbc[64];
+
+ int err = -EINVAL;
+ int singlekey = 0;
+
+ /* are keylens valid? */
+ ctx->ctx_valid = false;
+
+ switch (ctx->mode & 0xFF) {
+ case CRYPTO_MODE_SM4_GCM:
+ case CRYPTO_MODE_SM4_CCM:
+ case CRYPTO_MODE_NULL:
+ case CRYPTO_MODE_AES_GCM:
+ case CRYPTO_MODE_AES_CCM:
+ case CRYPTO_MODE_CHACHA20_POLY1305:
+ authkey = key;
+ authkeylen = 0;
+ enckey = key;
+ enckeylen = keylen;
+ ctx->keylen = keylen;
+ singlekey = 1;
+ goto skipover;
+ }
+
+ if (!RTA_OK(rta, keylen) ||^^^^^^^^^^^ This check validates that rta->rta_len is less than keylen.
+ rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM || + RTA_PAYLOAD(rta) < sizeof(*param)) + return -EINVAL; + + param = RTA_DATA(rta); + enckeylen = be32_to_cpu(param->enckeylen); + key += RTA_ALIGN(rta->rta_len); + keylen -= RTA_ALIGN(rta->rta_len);
However we're subtracting RTA_ALIGN() not rta->rta_len so there is a chance that this subtraction can make keylen negative (but it's unsigned so a large positive value). Both keylen and rta->rta_len would need have to not be multples of 4. For example, if they were both set to 9. (I'm not a domain expert so maybe here is checking for % 4 at a different level). A high positive value of keylen would lead to memory corruption later in the function. regards, dan carpenter
+
+ if (keylen < enckeylen)
+ return -EINVAL;
+
+ authkeylen = keylen - enckeylen;
+
+ /* enckey is at &key[authkeylen] and
+ * authkey is at &key[0]
+ */
+ authkey = &key[0];
+ enckey = &key[authkeylen];
+
+skipover:
+ /* detect RFC3686/4106 and trim from enckeylen(and copy salt..) */
+ if (ctx->mode & SPACC_MANGLE_IV_FLAG) {
+ switch (ctx->mode & 0x7F00) {
+ case SPACC_MANGLE_IV_RFC3686:
+ case SPACC_MANGLE_IV_RFC4106:
+ case SPACC_MANGLE_IV_RFC4543:
+ memcpy(ctx->csalt, enckey + enckeylen - 4, 4);
+ enckeylen -= 4;
+ break;
+ case SPACC_MANGLE_IV_RFC4309:
+ memcpy(ctx->csalt, enckey + enckeylen - 3, 3);
+ enckeylen -= 3;
+ break;
+ }
+ }
+
+ if (!singlekey) {
+ if (authkeylen > salg->mode->hashlen) {
+ dev_warn(ctx->dev, "Auth key size of %u is not valid\n",
+ authkeylen);
+ return -EINVAL;
+ }
+ }
+
+ if (!spacc_check_keylen(salg, enckeylen)) {
+ dev_warn(ctx->dev, "Enc key size of %u is not valid\n",
+ enckeylen);
+ return -EINVAL;
+ }
+
+ /* if we're already open close the handle since
+ * the size may have changed
+ */
+ if (ctx->handle != -1) {
+ priv = dev_get_drvdata(ctx->dev);
+ spacc_close(&priv->spacc, ctx->handle);
+ put_device(ctx->dev);
+ ctx->handle = -1;
+ }
+
+ /* Open a handle and
+ * search all devices for an open handle
+ */
+ priv = NULL;
+ priv = dev_get_drvdata(salg->dev[0]);
+
+ /* increase reference */
+ ctx->dev = get_device(salg->dev[0]);
+
+ /* check if its a valid mode ... */
+ if (spacc_isenabled(&priv->spacc, salg->mode->aead.ciph & 0xFF,
+ enckeylen) &&
+ spacc_isenabled(&priv->spacc,
+ salg->mode->aead.hash & 0xFF, authkeylen)) {
+ /* try to open spacc handle */
+ ctx->handle = spacc_open(&priv->spacc,
+ salg->mode->aead.ciph & 0xFF,
+ salg->mode->aead.hash & 0xFF,
+ -1, 0, spacc_aead_cb, tfm);
+ }
+
+ if (ctx->handle < 0) {
+ put_device(salg->dev[0]);
+ pr_debug("Failed to open SPAcc context\n");
+ return -EIO;
+ }
+
+ /* setup XCBC key */
+ if (salg->mode->aead.hash == CRYPTO_MODE_MAC_XCBC) {
+ err = spacc_compute_xcbc_key(&priv->spacc,
+ salg->mode->aead.hash,
+ ctx->handle, authkey,
+ authkeylen, xcbc);
+ if (err < 0) {
+ dev_warn(ctx->dev, "Failed to compute XCBC key: %d\n",
+ err);
+ return -EIO;
+ }
+ authkey = xcbc;
+ authkeylen = 48;
+ }
+
+ /* handle zero key/zero len DEC condition for SM4/AES GCM mode */
+ ctx->zero_key = 0;
+ if (!key[0]) {
+ int i, val = 0;
+
+ for (i = 0; i < keylen ; i++)
+ val += key[i];
+
+ if (val == 0)
+ ctx->zero_key = 1;
+ }
+
+ err = spacc_write_context(&priv->spacc, ctx->handle,
+ SPACC_CRYPTO_OPERATION, enckey,
+ enckeylen, NULL, 0);
+
+ if (err) {
+ dev_warn(ctx->dev,
+ "Could not write ciphering context: %d\n", err);
+ return -EIO;
+ }
+
+ if (!singlekey) {
+ err = spacc_write_context(&priv->spacc, ctx->handle,
+ SPACC_HASH_OPERATION, authkey,
+ authkeylen, NULL, 0);
+ if (err) {
+ dev_warn(ctx->dev,
+ "Could not write hashing context: %d\n", err);
+ return -EIO;
+ }
+ }
+
+ /* set expand key */
+ spacc_set_key_exp(&priv->spacc, ctx->handle);
+ ctx->ctx_valid = true;
+
+ memset(xcbc, 0, sizeof(xcbc));
+
+ /* copy key to ctx for fallback */
+ memcpy(ctx->key, key, keylen);
+
+ return 0;
+}