162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci *  linux/net/sunrpc/gss_krb5_crypto.c
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *  Copyright (c) 2000-2008 The Regents of the University of Michigan.
562306a36Sopenharmony_ci *  All rights reserved.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *  Andy Adamson   <andros@umich.edu>
862306a36Sopenharmony_ci *  Bruce Fields   <bfields@umich.edu>
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/*
1262306a36Sopenharmony_ci * Copyright (C) 1998 by the FundsXpress, INC.
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * All rights reserved.
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * Export of this software from the United States of America may require
1762306a36Sopenharmony_ci * a specific license from the United States Government.  It is the
1862306a36Sopenharmony_ci * responsibility of any person or organization contemplating export to
1962306a36Sopenharmony_ci * obtain such a license before exporting.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
2262306a36Sopenharmony_ci * distribute this software and its documentation for any purpose and
2362306a36Sopenharmony_ci * without fee is hereby granted, provided that the above copyright
2462306a36Sopenharmony_ci * notice appear in all copies and that both that copyright notice and
2562306a36Sopenharmony_ci * this permission notice appear in supporting documentation, and that
2662306a36Sopenharmony_ci * the name of FundsXpress. not be used in advertising or publicity pertaining
2762306a36Sopenharmony_ci * to distribution of the software without specific, written prior
2862306a36Sopenharmony_ci * permission.  FundsXpress makes no representations about the suitability of
2962306a36Sopenharmony_ci * this software for any purpose.  It is provided "as is" without express
3062306a36Sopenharmony_ci * or implied warranty.
3162306a36Sopenharmony_ci *
3262306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
3362306a36Sopenharmony_ci * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
3462306a36Sopenharmony_ci * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
3562306a36Sopenharmony_ci */
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#include <crypto/algapi.h>
3862306a36Sopenharmony_ci#include <crypto/hash.h>
3962306a36Sopenharmony_ci#include <crypto/skcipher.h>
4062306a36Sopenharmony_ci#include <linux/err.h>
4162306a36Sopenharmony_ci#include <linux/types.h>
4262306a36Sopenharmony_ci#include <linux/mm.h>
4362306a36Sopenharmony_ci#include <linux/scatterlist.h>
4462306a36Sopenharmony_ci#include <linux/highmem.h>
4562306a36Sopenharmony_ci#include <linux/pagemap.h>
4662306a36Sopenharmony_ci#include <linux/random.h>
4762306a36Sopenharmony_ci#include <linux/sunrpc/gss_krb5.h>
4862306a36Sopenharmony_ci#include <linux/sunrpc/xdr.h>
4962306a36Sopenharmony_ci#include <kunit/visibility.h>
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#include "gss_krb5_internal.h"
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
5462306a36Sopenharmony_ci# define RPCDBG_FACILITY        RPCDBG_AUTH
5562306a36Sopenharmony_ci#endif
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/**
5862306a36Sopenharmony_ci * krb5_make_confounder - Generate a confounder string
5962306a36Sopenharmony_ci * @p: memory location into which to write the string
6062306a36Sopenharmony_ci * @conflen: string length to write, in octets
6162306a36Sopenharmony_ci *
6262306a36Sopenharmony_ci * RFCs 1964 and 3961 mention only "a random confounder" without going
6362306a36Sopenharmony_ci * into detail about its function or cryptographic requirements. The
6462306a36Sopenharmony_ci * assumed purpose is to prevent repeated encryption of a plaintext with
6562306a36Sopenharmony_ci * the same key from generating the same ciphertext. It is also used to
6662306a36Sopenharmony_ci * pad minimum plaintext length to at least a single cipher block.
6762306a36Sopenharmony_ci *
6862306a36Sopenharmony_ci * However, in situations like the GSS Kerberos 5 mechanism, where the
6962306a36Sopenharmony_ci * encryption IV is always all zeroes, the confounder also effectively
7062306a36Sopenharmony_ci * functions like an IV. Thus, not only must it be unique from message
7162306a36Sopenharmony_ci * to message, but it must also be difficult to predict. Otherwise an
7262306a36Sopenharmony_ci * attacker can correlate the confounder to previous or future values,
7362306a36Sopenharmony_ci * making the encryption easier to break.
7462306a36Sopenharmony_ci *
7562306a36Sopenharmony_ci * Given that the primary consumer of this encryption mechanism is a
7662306a36Sopenharmony_ci * network storage protocol, a type of traffic that often carries
7762306a36Sopenharmony_ci * predictable payloads (eg, all zeroes when reading unallocated blocks
7862306a36Sopenharmony_ci * from a file), our confounder generation has to be cryptographically
7962306a36Sopenharmony_ci * strong.
8062306a36Sopenharmony_ci */
8162306a36Sopenharmony_civoid krb5_make_confounder(u8 *p, int conflen)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	get_random_bytes(p, conflen);
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci/**
8762306a36Sopenharmony_ci * krb5_encrypt - simple encryption of an RPCSEC GSS payload
8862306a36Sopenharmony_ci * @tfm: initialized cipher transform
8962306a36Sopenharmony_ci * @iv: pointer to an IV
9062306a36Sopenharmony_ci * @in: plaintext to encrypt
9162306a36Sopenharmony_ci * @out: OUT: ciphertext
9262306a36Sopenharmony_ci * @length: length of input and output buffers, in bytes
9362306a36Sopenharmony_ci *
9462306a36Sopenharmony_ci * @iv may be NULL to force the use of an all-zero IV.
9562306a36Sopenharmony_ci * The buffer containing the IV must be as large as the
9662306a36Sopenharmony_ci * cipher's ivsize.
9762306a36Sopenharmony_ci *
9862306a36Sopenharmony_ci * Return values:
9962306a36Sopenharmony_ci *   %0: @in successfully encrypted into @out
10062306a36Sopenharmony_ci *   negative errno: @in not encrypted
10162306a36Sopenharmony_ci */
10262306a36Sopenharmony_ciu32
10362306a36Sopenharmony_cikrb5_encrypt(
10462306a36Sopenharmony_ci	struct crypto_sync_skcipher *tfm,
10562306a36Sopenharmony_ci	void * iv,
10662306a36Sopenharmony_ci	void * in,
10762306a36Sopenharmony_ci	void * out,
10862306a36Sopenharmony_ci	int length)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	u32 ret = -EINVAL;
11162306a36Sopenharmony_ci	struct scatterlist sg[1];
11262306a36Sopenharmony_ci	u8 local_iv[GSS_KRB5_MAX_BLOCKSIZE] = {0};
11362306a36Sopenharmony_ci	SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	if (length % crypto_sync_skcipher_blocksize(tfm) != 0)
11662306a36Sopenharmony_ci		goto out;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	if (crypto_sync_skcipher_ivsize(tfm) > GSS_KRB5_MAX_BLOCKSIZE) {
11962306a36Sopenharmony_ci		dprintk("RPC:       gss_k5encrypt: tfm iv size too large %d\n",
12062306a36Sopenharmony_ci			crypto_sync_skcipher_ivsize(tfm));
12162306a36Sopenharmony_ci		goto out;
12262306a36Sopenharmony_ci	}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	if (iv)
12562306a36Sopenharmony_ci		memcpy(local_iv, iv, crypto_sync_skcipher_ivsize(tfm));
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	memcpy(out, in, length);
12862306a36Sopenharmony_ci	sg_init_one(sg, out, length);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	skcipher_request_set_sync_tfm(req, tfm);
13162306a36Sopenharmony_ci	skcipher_request_set_callback(req, 0, NULL, NULL);
13262306a36Sopenharmony_ci	skcipher_request_set_crypt(req, sg, sg, length, local_iv);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	ret = crypto_skcipher_encrypt(req);
13562306a36Sopenharmony_ci	skcipher_request_zero(req);
13662306a36Sopenharmony_ciout:
13762306a36Sopenharmony_ci	dprintk("RPC:       krb5_encrypt returns %d\n", ret);
13862306a36Sopenharmony_ci	return ret;
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/**
14262306a36Sopenharmony_ci * krb5_decrypt - simple decryption of an RPCSEC GSS payload
14362306a36Sopenharmony_ci * @tfm: initialized cipher transform
14462306a36Sopenharmony_ci * @iv: pointer to an IV
14562306a36Sopenharmony_ci * @in: ciphertext to decrypt
14662306a36Sopenharmony_ci * @out: OUT: plaintext
14762306a36Sopenharmony_ci * @length: length of input and output buffers, in bytes
14862306a36Sopenharmony_ci *
14962306a36Sopenharmony_ci * @iv may be NULL to force the use of an all-zero IV.
15062306a36Sopenharmony_ci * The buffer containing the IV must be as large as the
15162306a36Sopenharmony_ci * cipher's ivsize.
15262306a36Sopenharmony_ci *
15362306a36Sopenharmony_ci * Return values:
15462306a36Sopenharmony_ci *   %0: @in successfully decrypted into @out
15562306a36Sopenharmony_ci *   negative errno: @in not decrypted
15662306a36Sopenharmony_ci */
15762306a36Sopenharmony_ciu32
15862306a36Sopenharmony_cikrb5_decrypt(
15962306a36Sopenharmony_ci     struct crypto_sync_skcipher *tfm,
16062306a36Sopenharmony_ci     void * iv,
16162306a36Sopenharmony_ci     void * in,
16262306a36Sopenharmony_ci     void * out,
16362306a36Sopenharmony_ci     int length)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	u32 ret = -EINVAL;
16662306a36Sopenharmony_ci	struct scatterlist sg[1];
16762306a36Sopenharmony_ci	u8 local_iv[GSS_KRB5_MAX_BLOCKSIZE] = {0};
16862306a36Sopenharmony_ci	SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	if (length % crypto_sync_skcipher_blocksize(tfm) != 0)
17162306a36Sopenharmony_ci		goto out;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	if (crypto_sync_skcipher_ivsize(tfm) > GSS_KRB5_MAX_BLOCKSIZE) {
17462306a36Sopenharmony_ci		dprintk("RPC:       gss_k5decrypt: tfm iv size too large %d\n",
17562306a36Sopenharmony_ci			crypto_sync_skcipher_ivsize(tfm));
17662306a36Sopenharmony_ci		goto out;
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci	if (iv)
17962306a36Sopenharmony_ci		memcpy(local_iv, iv, crypto_sync_skcipher_ivsize(tfm));
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	memcpy(out, in, length);
18262306a36Sopenharmony_ci	sg_init_one(sg, out, length);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	skcipher_request_set_sync_tfm(req, tfm);
18562306a36Sopenharmony_ci	skcipher_request_set_callback(req, 0, NULL, NULL);
18662306a36Sopenharmony_ci	skcipher_request_set_crypt(req, sg, sg, length, local_iv);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	ret = crypto_skcipher_decrypt(req);
18962306a36Sopenharmony_ci	skcipher_request_zero(req);
19062306a36Sopenharmony_ciout:
19162306a36Sopenharmony_ci	dprintk("RPC:       gss_k5decrypt returns %d\n",ret);
19262306a36Sopenharmony_ci	return ret;
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic int
19662306a36Sopenharmony_cichecksummer(struct scatterlist *sg, void *data)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	struct ahash_request *req = data;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	ahash_request_set_crypt(req, sg, NULL, sg->length);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	return crypto_ahash_update(req);
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci/*
20662306a36Sopenharmony_ci * checksum the plaintext data and hdrlen bytes of the token header
20762306a36Sopenharmony_ci * The checksum is performed over the first 8 bytes of the
20862306a36Sopenharmony_ci * gss token header and then over the data body
20962306a36Sopenharmony_ci */
21062306a36Sopenharmony_ciu32
21162306a36Sopenharmony_cimake_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
21262306a36Sopenharmony_ci	      struct xdr_buf *body, int body_offset, u8 *cksumkey,
21362306a36Sopenharmony_ci	      unsigned int usage, struct xdr_netobj *cksumout)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	struct crypto_ahash *tfm;
21662306a36Sopenharmony_ci	struct ahash_request *req;
21762306a36Sopenharmony_ci	struct scatterlist              sg[1];
21862306a36Sopenharmony_ci	int err = -1;
21962306a36Sopenharmony_ci	u8 *checksumdata;
22062306a36Sopenharmony_ci	unsigned int checksumlen;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	if (cksumout->len < kctx->gk5e->cksumlength) {
22362306a36Sopenharmony_ci		dprintk("%s: checksum buffer length, %u, too small for %s\n",
22462306a36Sopenharmony_ci			__func__, cksumout->len, kctx->gk5e->name);
22562306a36Sopenharmony_ci		return GSS_S_FAILURE;
22662306a36Sopenharmony_ci	}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	checksumdata = kmalloc(GSS_KRB5_MAX_CKSUM_LEN, GFP_KERNEL);
22962306a36Sopenharmony_ci	if (checksumdata == NULL)
23062306a36Sopenharmony_ci		return GSS_S_FAILURE;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	tfm = crypto_alloc_ahash(kctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC);
23362306a36Sopenharmony_ci	if (IS_ERR(tfm))
23462306a36Sopenharmony_ci		goto out_free_cksum;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	req = ahash_request_alloc(tfm, GFP_KERNEL);
23762306a36Sopenharmony_ci	if (!req)
23862306a36Sopenharmony_ci		goto out_free_ahash;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	checksumlen = crypto_ahash_digestsize(tfm);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	if (cksumkey != NULL) {
24562306a36Sopenharmony_ci		err = crypto_ahash_setkey(tfm, cksumkey,
24662306a36Sopenharmony_ci					  kctx->gk5e->keylength);
24762306a36Sopenharmony_ci		if (err)
24862306a36Sopenharmony_ci			goto out;
24962306a36Sopenharmony_ci	}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	err = crypto_ahash_init(req);
25262306a36Sopenharmony_ci	if (err)
25362306a36Sopenharmony_ci		goto out;
25462306a36Sopenharmony_ci	sg_init_one(sg, header, hdrlen);
25562306a36Sopenharmony_ci	ahash_request_set_crypt(req, sg, NULL, hdrlen);
25662306a36Sopenharmony_ci	err = crypto_ahash_update(req);
25762306a36Sopenharmony_ci	if (err)
25862306a36Sopenharmony_ci		goto out;
25962306a36Sopenharmony_ci	err = xdr_process_buf(body, body_offset, body->len - body_offset,
26062306a36Sopenharmony_ci			      checksummer, req);
26162306a36Sopenharmony_ci	if (err)
26262306a36Sopenharmony_ci		goto out;
26362306a36Sopenharmony_ci	ahash_request_set_crypt(req, NULL, checksumdata, 0);
26462306a36Sopenharmony_ci	err = crypto_ahash_final(req);
26562306a36Sopenharmony_ci	if (err)
26662306a36Sopenharmony_ci		goto out;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	switch (kctx->gk5e->ctype) {
26962306a36Sopenharmony_ci	case CKSUMTYPE_RSA_MD5:
27062306a36Sopenharmony_ci		err = krb5_encrypt(kctx->seq, NULL, checksumdata,
27162306a36Sopenharmony_ci				   checksumdata, checksumlen);
27262306a36Sopenharmony_ci		if (err)
27362306a36Sopenharmony_ci			goto out;
27462306a36Sopenharmony_ci		memcpy(cksumout->data,
27562306a36Sopenharmony_ci		       checksumdata + checksumlen - kctx->gk5e->cksumlength,
27662306a36Sopenharmony_ci		       kctx->gk5e->cksumlength);
27762306a36Sopenharmony_ci		break;
27862306a36Sopenharmony_ci	case CKSUMTYPE_HMAC_SHA1_DES3:
27962306a36Sopenharmony_ci		memcpy(cksumout->data, checksumdata, kctx->gk5e->cksumlength);
28062306a36Sopenharmony_ci		break;
28162306a36Sopenharmony_ci	default:
28262306a36Sopenharmony_ci		BUG();
28362306a36Sopenharmony_ci		break;
28462306a36Sopenharmony_ci	}
28562306a36Sopenharmony_ci	cksumout->len = kctx->gk5e->cksumlength;
28662306a36Sopenharmony_ciout:
28762306a36Sopenharmony_ci	ahash_request_free(req);
28862306a36Sopenharmony_ciout_free_ahash:
28962306a36Sopenharmony_ci	crypto_free_ahash(tfm);
29062306a36Sopenharmony_ciout_free_cksum:
29162306a36Sopenharmony_ci	kfree(checksumdata);
29262306a36Sopenharmony_ci	return err ? GSS_S_FAILURE : 0;
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci/**
29662306a36Sopenharmony_ci * gss_krb5_checksum - Compute the MAC for a GSS Wrap or MIC token
29762306a36Sopenharmony_ci * @tfm: an initialized hash transform
29862306a36Sopenharmony_ci * @header: pointer to a buffer containing the token header, or NULL
29962306a36Sopenharmony_ci * @hdrlen: number of octets in @header
30062306a36Sopenharmony_ci * @body: xdr_buf containing an RPC message (body.len is the message length)
30162306a36Sopenharmony_ci * @body_offset: byte offset into @body to start checksumming
30262306a36Sopenharmony_ci * @cksumout: OUT: a buffer to be filled in with the computed HMAC
30362306a36Sopenharmony_ci *
30462306a36Sopenharmony_ci * Usually expressed as H = HMAC(K, message)[1..h] .
30562306a36Sopenharmony_ci *
30662306a36Sopenharmony_ci * Caller provides the truncation length of the output token (h) in
30762306a36Sopenharmony_ci * cksumout.len.
30862306a36Sopenharmony_ci *
30962306a36Sopenharmony_ci * Return values:
31062306a36Sopenharmony_ci *   %GSS_S_COMPLETE: Digest computed, @cksumout filled in
31162306a36Sopenharmony_ci *   %GSS_S_FAILURE: Call failed
31262306a36Sopenharmony_ci */
31362306a36Sopenharmony_ciu32
31462306a36Sopenharmony_cigss_krb5_checksum(struct crypto_ahash *tfm, char *header, int hdrlen,
31562306a36Sopenharmony_ci		  const struct xdr_buf *body, int body_offset,
31662306a36Sopenharmony_ci		  struct xdr_netobj *cksumout)
31762306a36Sopenharmony_ci{
31862306a36Sopenharmony_ci	struct ahash_request *req;
31962306a36Sopenharmony_ci	int err = -ENOMEM;
32062306a36Sopenharmony_ci	u8 *checksumdata;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	checksumdata = kmalloc(crypto_ahash_digestsize(tfm), GFP_KERNEL);
32362306a36Sopenharmony_ci	if (!checksumdata)
32462306a36Sopenharmony_ci		return GSS_S_FAILURE;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	req = ahash_request_alloc(tfm, GFP_KERNEL);
32762306a36Sopenharmony_ci	if (!req)
32862306a36Sopenharmony_ci		goto out_free_cksum;
32962306a36Sopenharmony_ci	ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
33062306a36Sopenharmony_ci	err = crypto_ahash_init(req);
33162306a36Sopenharmony_ci	if (err)
33262306a36Sopenharmony_ci		goto out_free_ahash;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	/*
33562306a36Sopenharmony_ci	 * Per RFC 4121 Section 4.2.4, the checksum is performed over the
33662306a36Sopenharmony_ci	 * data body first, then over the octets in "header".
33762306a36Sopenharmony_ci	 */
33862306a36Sopenharmony_ci	err = xdr_process_buf(body, body_offset, body->len - body_offset,
33962306a36Sopenharmony_ci			      checksummer, req);
34062306a36Sopenharmony_ci	if (err)
34162306a36Sopenharmony_ci		goto out_free_ahash;
34262306a36Sopenharmony_ci	if (header) {
34362306a36Sopenharmony_ci		struct scatterlist sg[1];
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci		sg_init_one(sg, header, hdrlen);
34662306a36Sopenharmony_ci		ahash_request_set_crypt(req, sg, NULL, hdrlen);
34762306a36Sopenharmony_ci		err = crypto_ahash_update(req);
34862306a36Sopenharmony_ci		if (err)
34962306a36Sopenharmony_ci			goto out_free_ahash;
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	ahash_request_set_crypt(req, NULL, checksumdata, 0);
35362306a36Sopenharmony_ci	err = crypto_ahash_final(req);
35462306a36Sopenharmony_ci	if (err)
35562306a36Sopenharmony_ci		goto out_free_ahash;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	memcpy(cksumout->data, checksumdata,
35862306a36Sopenharmony_ci	       min_t(int, cksumout->len, crypto_ahash_digestsize(tfm)));
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ciout_free_ahash:
36162306a36Sopenharmony_ci	ahash_request_free(req);
36262306a36Sopenharmony_ciout_free_cksum:
36362306a36Sopenharmony_ci	kfree_sensitive(checksumdata);
36462306a36Sopenharmony_ci	return err ? GSS_S_FAILURE : GSS_S_COMPLETE;
36562306a36Sopenharmony_ci}
36662306a36Sopenharmony_ciEXPORT_SYMBOL_IF_KUNIT(gss_krb5_checksum);
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_cistruct encryptor_desc {
36962306a36Sopenharmony_ci	u8 iv[GSS_KRB5_MAX_BLOCKSIZE];
37062306a36Sopenharmony_ci	struct skcipher_request *req;
37162306a36Sopenharmony_ci	int pos;
37262306a36Sopenharmony_ci	struct xdr_buf *outbuf;
37362306a36Sopenharmony_ci	struct page **pages;
37462306a36Sopenharmony_ci	struct scatterlist infrags[4];
37562306a36Sopenharmony_ci	struct scatterlist outfrags[4];
37662306a36Sopenharmony_ci	int fragno;
37762306a36Sopenharmony_ci	int fraglen;
37862306a36Sopenharmony_ci};
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic int
38162306a36Sopenharmony_ciencryptor(struct scatterlist *sg, void *data)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	struct encryptor_desc *desc = data;
38462306a36Sopenharmony_ci	struct xdr_buf *outbuf = desc->outbuf;
38562306a36Sopenharmony_ci	struct crypto_sync_skcipher *tfm =
38662306a36Sopenharmony_ci		crypto_sync_skcipher_reqtfm(desc->req);
38762306a36Sopenharmony_ci	struct page *in_page;
38862306a36Sopenharmony_ci	int thislen = desc->fraglen + sg->length;
38962306a36Sopenharmony_ci	int fraglen, ret;
39062306a36Sopenharmony_ci	int page_pos;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	/* Worst case is 4 fragments: head, end of page 1, start
39362306a36Sopenharmony_ci	 * of page 2, tail.  Anything more is a bug. */
39462306a36Sopenharmony_ci	BUG_ON(desc->fragno > 3);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	page_pos = desc->pos - outbuf->head[0].iov_len;
39762306a36Sopenharmony_ci	if (page_pos >= 0 && page_pos < outbuf->page_len) {
39862306a36Sopenharmony_ci		/* pages are not in place: */
39962306a36Sopenharmony_ci		int i = (page_pos + outbuf->page_base) >> PAGE_SHIFT;
40062306a36Sopenharmony_ci		in_page = desc->pages[i];
40162306a36Sopenharmony_ci	} else {
40262306a36Sopenharmony_ci		in_page = sg_page(sg);
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci	sg_set_page(&desc->infrags[desc->fragno], in_page, sg->length,
40562306a36Sopenharmony_ci		    sg->offset);
40662306a36Sopenharmony_ci	sg_set_page(&desc->outfrags[desc->fragno], sg_page(sg), sg->length,
40762306a36Sopenharmony_ci		    sg->offset);
40862306a36Sopenharmony_ci	desc->fragno++;
40962306a36Sopenharmony_ci	desc->fraglen += sg->length;
41062306a36Sopenharmony_ci	desc->pos += sg->length;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	fraglen = thislen & (crypto_sync_skcipher_blocksize(tfm) - 1);
41362306a36Sopenharmony_ci	thislen -= fraglen;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	if (thislen == 0)
41662306a36Sopenharmony_ci		return 0;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	sg_mark_end(&desc->infrags[desc->fragno - 1]);
41962306a36Sopenharmony_ci	sg_mark_end(&desc->outfrags[desc->fragno - 1]);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	skcipher_request_set_crypt(desc->req, desc->infrags, desc->outfrags,
42262306a36Sopenharmony_ci				   thislen, desc->iv);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	ret = crypto_skcipher_encrypt(desc->req);
42562306a36Sopenharmony_ci	if (ret)
42662306a36Sopenharmony_ci		return ret;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	sg_init_table(desc->infrags, 4);
42962306a36Sopenharmony_ci	sg_init_table(desc->outfrags, 4);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	if (fraglen) {
43262306a36Sopenharmony_ci		sg_set_page(&desc->outfrags[0], sg_page(sg), fraglen,
43362306a36Sopenharmony_ci				sg->offset + sg->length - fraglen);
43462306a36Sopenharmony_ci		desc->infrags[0] = desc->outfrags[0];
43562306a36Sopenharmony_ci		sg_assign_page(&desc->infrags[0], in_page);
43662306a36Sopenharmony_ci		desc->fragno = 1;
43762306a36Sopenharmony_ci		desc->fraglen = fraglen;
43862306a36Sopenharmony_ci	} else {
43962306a36Sopenharmony_ci		desc->fragno = 0;
44062306a36Sopenharmony_ci		desc->fraglen = 0;
44162306a36Sopenharmony_ci	}
44262306a36Sopenharmony_ci	return 0;
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ciint
44662306a36Sopenharmony_cigss_encrypt_xdr_buf(struct crypto_sync_skcipher *tfm, struct xdr_buf *buf,
44762306a36Sopenharmony_ci		    int offset, struct page **pages)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	int ret;
45062306a36Sopenharmony_ci	struct encryptor_desc desc;
45162306a36Sopenharmony_ci	SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	BUG_ON((buf->len - offset) % crypto_sync_skcipher_blocksize(tfm) != 0);
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	skcipher_request_set_sync_tfm(req, tfm);
45662306a36Sopenharmony_ci	skcipher_request_set_callback(req, 0, NULL, NULL);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	memset(desc.iv, 0, sizeof(desc.iv));
45962306a36Sopenharmony_ci	desc.req = req;
46062306a36Sopenharmony_ci	desc.pos = offset;
46162306a36Sopenharmony_ci	desc.outbuf = buf;
46262306a36Sopenharmony_ci	desc.pages = pages;
46362306a36Sopenharmony_ci	desc.fragno = 0;
46462306a36Sopenharmony_ci	desc.fraglen = 0;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	sg_init_table(desc.infrags, 4);
46762306a36Sopenharmony_ci	sg_init_table(desc.outfrags, 4);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	ret = xdr_process_buf(buf, offset, buf->len - offset, encryptor, &desc);
47062306a36Sopenharmony_ci	skcipher_request_zero(req);
47162306a36Sopenharmony_ci	return ret;
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_cistruct decryptor_desc {
47562306a36Sopenharmony_ci	u8 iv[GSS_KRB5_MAX_BLOCKSIZE];
47662306a36Sopenharmony_ci	struct skcipher_request *req;
47762306a36Sopenharmony_ci	struct scatterlist frags[4];
47862306a36Sopenharmony_ci	int fragno;
47962306a36Sopenharmony_ci	int fraglen;
48062306a36Sopenharmony_ci};
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_cistatic int
48362306a36Sopenharmony_cidecryptor(struct scatterlist *sg, void *data)
48462306a36Sopenharmony_ci{
48562306a36Sopenharmony_ci	struct decryptor_desc *desc = data;
48662306a36Sopenharmony_ci	int thislen = desc->fraglen + sg->length;
48762306a36Sopenharmony_ci	struct crypto_sync_skcipher *tfm =
48862306a36Sopenharmony_ci		crypto_sync_skcipher_reqtfm(desc->req);
48962306a36Sopenharmony_ci	int fraglen, ret;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	/* Worst case is 4 fragments: head, end of page 1, start
49262306a36Sopenharmony_ci	 * of page 2, tail.  Anything more is a bug. */
49362306a36Sopenharmony_ci	BUG_ON(desc->fragno > 3);
49462306a36Sopenharmony_ci	sg_set_page(&desc->frags[desc->fragno], sg_page(sg), sg->length,
49562306a36Sopenharmony_ci		    sg->offset);
49662306a36Sopenharmony_ci	desc->fragno++;
49762306a36Sopenharmony_ci	desc->fraglen += sg->length;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	fraglen = thislen & (crypto_sync_skcipher_blocksize(tfm) - 1);
50062306a36Sopenharmony_ci	thislen -= fraglen;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	if (thislen == 0)
50362306a36Sopenharmony_ci		return 0;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	sg_mark_end(&desc->frags[desc->fragno - 1]);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	skcipher_request_set_crypt(desc->req, desc->frags, desc->frags,
50862306a36Sopenharmony_ci				   thislen, desc->iv);
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	ret = crypto_skcipher_decrypt(desc->req);
51162306a36Sopenharmony_ci	if (ret)
51262306a36Sopenharmony_ci		return ret;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	sg_init_table(desc->frags, 4);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	if (fraglen) {
51762306a36Sopenharmony_ci		sg_set_page(&desc->frags[0], sg_page(sg), fraglen,
51862306a36Sopenharmony_ci				sg->offset + sg->length - fraglen);
51962306a36Sopenharmony_ci		desc->fragno = 1;
52062306a36Sopenharmony_ci		desc->fraglen = fraglen;
52162306a36Sopenharmony_ci	} else {
52262306a36Sopenharmony_ci		desc->fragno = 0;
52362306a36Sopenharmony_ci		desc->fraglen = 0;
52462306a36Sopenharmony_ci	}
52562306a36Sopenharmony_ci	return 0;
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ciint
52962306a36Sopenharmony_cigss_decrypt_xdr_buf(struct crypto_sync_skcipher *tfm, struct xdr_buf *buf,
53062306a36Sopenharmony_ci		    int offset)
53162306a36Sopenharmony_ci{
53262306a36Sopenharmony_ci	int ret;
53362306a36Sopenharmony_ci	struct decryptor_desc desc;
53462306a36Sopenharmony_ci	SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	/* XXXJBF: */
53762306a36Sopenharmony_ci	BUG_ON((buf->len - offset) % crypto_sync_skcipher_blocksize(tfm) != 0);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	skcipher_request_set_sync_tfm(req, tfm);
54062306a36Sopenharmony_ci	skcipher_request_set_callback(req, 0, NULL, NULL);
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	memset(desc.iv, 0, sizeof(desc.iv));
54362306a36Sopenharmony_ci	desc.req = req;
54462306a36Sopenharmony_ci	desc.fragno = 0;
54562306a36Sopenharmony_ci	desc.fraglen = 0;
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	sg_init_table(desc.frags, 4);
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	ret = xdr_process_buf(buf, offset, buf->len - offset, decryptor, &desc);
55062306a36Sopenharmony_ci	skcipher_request_zero(req);
55162306a36Sopenharmony_ci	return ret;
55262306a36Sopenharmony_ci}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci/*
55562306a36Sopenharmony_ci * This function makes the assumption that it was ultimately called
55662306a36Sopenharmony_ci * from gss_wrap().
55762306a36Sopenharmony_ci *
55862306a36Sopenharmony_ci * The client auth_gss code moves any existing tail data into a
55962306a36Sopenharmony_ci * separate page before calling gss_wrap.
56062306a36Sopenharmony_ci * The server svcauth_gss code ensures that both the head and the
56162306a36Sopenharmony_ci * tail have slack space of RPC_MAX_AUTH_SIZE before calling gss_wrap.
56262306a36Sopenharmony_ci *
56362306a36Sopenharmony_ci * Even with that guarantee, this function may be called more than
56462306a36Sopenharmony_ci * once in the processing of gss_wrap().  The best we can do is
56562306a36Sopenharmony_ci * verify at compile-time (see GSS_KRB5_SLACK_CHECK) that the
56662306a36Sopenharmony_ci * largest expected shift will fit within RPC_MAX_AUTH_SIZE.
56762306a36Sopenharmony_ci * At run-time we can verify that a single invocation of this
56862306a36Sopenharmony_ci * function doesn't attempt to use more the RPC_MAX_AUTH_SIZE.
56962306a36Sopenharmony_ci */
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ciint
57262306a36Sopenharmony_cixdr_extend_head(struct xdr_buf *buf, unsigned int base, unsigned int shiftlen)
57362306a36Sopenharmony_ci{
57462306a36Sopenharmony_ci	u8 *p;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	if (shiftlen == 0)
57762306a36Sopenharmony_ci		return 0;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	BUG_ON(shiftlen > RPC_MAX_AUTH_SIZE);
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	p = buf->head[0].iov_base + base;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	memmove(p + shiftlen, p, buf->head[0].iov_len - base);
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	buf->head[0].iov_len += shiftlen;
58662306a36Sopenharmony_ci	buf->len += shiftlen;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	return 0;
58962306a36Sopenharmony_ci}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_cistatic u32
59262306a36Sopenharmony_cigss_krb5_cts_crypt(struct crypto_sync_skcipher *cipher, struct xdr_buf *buf,
59362306a36Sopenharmony_ci		   u32 offset, u8 *iv, struct page **pages, int encrypt)
59462306a36Sopenharmony_ci{
59562306a36Sopenharmony_ci	u32 ret;
59662306a36Sopenharmony_ci	struct scatterlist sg[1];
59762306a36Sopenharmony_ci	SYNC_SKCIPHER_REQUEST_ON_STACK(req, cipher);
59862306a36Sopenharmony_ci	u8 *data;
59962306a36Sopenharmony_ci	struct page **save_pages;
60062306a36Sopenharmony_ci	u32 len = buf->len - offset;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	if (len > GSS_KRB5_MAX_BLOCKSIZE * 2) {
60362306a36Sopenharmony_ci		WARN_ON(0);
60462306a36Sopenharmony_ci		return -ENOMEM;
60562306a36Sopenharmony_ci	}
60662306a36Sopenharmony_ci	data = kmalloc(GSS_KRB5_MAX_BLOCKSIZE * 2, GFP_KERNEL);
60762306a36Sopenharmony_ci	if (!data)
60862306a36Sopenharmony_ci		return -ENOMEM;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	/*
61162306a36Sopenharmony_ci	 * For encryption, we want to read from the cleartext
61262306a36Sopenharmony_ci	 * page cache pages, and write the encrypted data to
61362306a36Sopenharmony_ci	 * the supplied xdr_buf pages.
61462306a36Sopenharmony_ci	 */
61562306a36Sopenharmony_ci	save_pages = buf->pages;
61662306a36Sopenharmony_ci	if (encrypt)
61762306a36Sopenharmony_ci		buf->pages = pages;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	ret = read_bytes_from_xdr_buf(buf, offset, data, len);
62062306a36Sopenharmony_ci	buf->pages = save_pages;
62162306a36Sopenharmony_ci	if (ret)
62262306a36Sopenharmony_ci		goto out;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	sg_init_one(sg, data, len);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	skcipher_request_set_sync_tfm(req, cipher);
62762306a36Sopenharmony_ci	skcipher_request_set_callback(req, 0, NULL, NULL);
62862306a36Sopenharmony_ci	skcipher_request_set_crypt(req, sg, sg, len, iv);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	if (encrypt)
63162306a36Sopenharmony_ci		ret = crypto_skcipher_encrypt(req);
63262306a36Sopenharmony_ci	else
63362306a36Sopenharmony_ci		ret = crypto_skcipher_decrypt(req);
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	skcipher_request_zero(req);
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	if (ret)
63862306a36Sopenharmony_ci		goto out;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	ret = write_bytes_to_xdr_buf(buf, offset, data, len);
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_KUNIT)
64362306a36Sopenharmony_ci	/*
64462306a36Sopenharmony_ci	 * CBC-CTS does not define an output IV but RFC 3962 defines it as the
64562306a36Sopenharmony_ci	 * penultimate block of ciphertext, so copy that into the IV buffer
64662306a36Sopenharmony_ci	 * before returning.
64762306a36Sopenharmony_ci	 */
64862306a36Sopenharmony_ci	if (encrypt)
64962306a36Sopenharmony_ci		memcpy(iv, data, crypto_sync_skcipher_ivsize(cipher));
65062306a36Sopenharmony_ci#endif
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ciout:
65362306a36Sopenharmony_ci	kfree(data);
65462306a36Sopenharmony_ci	return ret;
65562306a36Sopenharmony_ci}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci/**
65862306a36Sopenharmony_ci * krb5_cbc_cts_encrypt - encrypt in CBC mode with CTS
65962306a36Sopenharmony_ci * @cts_tfm: CBC cipher with CTS
66062306a36Sopenharmony_ci * @cbc_tfm: base CBC cipher
66162306a36Sopenharmony_ci * @offset: starting byte offset for plaintext
66262306a36Sopenharmony_ci * @buf: OUT: output buffer
66362306a36Sopenharmony_ci * @pages: plaintext
66462306a36Sopenharmony_ci * @iv: output CBC initialization vector, or NULL
66562306a36Sopenharmony_ci * @ivsize: size of @iv, in octets
66662306a36Sopenharmony_ci *
66762306a36Sopenharmony_ci * To provide confidentiality, encrypt using cipher block chaining
66862306a36Sopenharmony_ci * with ciphertext stealing. Message integrity is handled separately.
66962306a36Sopenharmony_ci *
67062306a36Sopenharmony_ci * Return values:
67162306a36Sopenharmony_ci *   %0: encryption successful
67262306a36Sopenharmony_ci *   negative errno: encryption could not be completed
67362306a36Sopenharmony_ci */
67462306a36Sopenharmony_ciVISIBLE_IF_KUNIT
67562306a36Sopenharmony_ciint krb5_cbc_cts_encrypt(struct crypto_sync_skcipher *cts_tfm,
67662306a36Sopenharmony_ci			 struct crypto_sync_skcipher *cbc_tfm,
67762306a36Sopenharmony_ci			 u32 offset, struct xdr_buf *buf, struct page **pages,
67862306a36Sopenharmony_ci			 u8 *iv, unsigned int ivsize)
67962306a36Sopenharmony_ci{
68062306a36Sopenharmony_ci	u32 blocksize, nbytes, nblocks, cbcbytes;
68162306a36Sopenharmony_ci	struct encryptor_desc desc;
68262306a36Sopenharmony_ci	int err;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	blocksize = crypto_sync_skcipher_blocksize(cts_tfm);
68562306a36Sopenharmony_ci	nbytes = buf->len - offset;
68662306a36Sopenharmony_ci	nblocks = (nbytes + blocksize - 1) / blocksize;
68762306a36Sopenharmony_ci	cbcbytes = 0;
68862306a36Sopenharmony_ci	if (nblocks > 2)
68962306a36Sopenharmony_ci		cbcbytes = (nblocks - 2) * blocksize;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	memset(desc.iv, 0, sizeof(desc.iv));
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	/* Handle block-sized chunks of plaintext with CBC. */
69462306a36Sopenharmony_ci	if (cbcbytes) {
69562306a36Sopenharmony_ci		SYNC_SKCIPHER_REQUEST_ON_STACK(req, cbc_tfm);
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci		desc.pos = offset;
69862306a36Sopenharmony_ci		desc.fragno = 0;
69962306a36Sopenharmony_ci		desc.fraglen = 0;
70062306a36Sopenharmony_ci		desc.pages = pages;
70162306a36Sopenharmony_ci		desc.outbuf = buf;
70262306a36Sopenharmony_ci		desc.req = req;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci		skcipher_request_set_sync_tfm(req, cbc_tfm);
70562306a36Sopenharmony_ci		skcipher_request_set_callback(req, 0, NULL, NULL);
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci		sg_init_table(desc.infrags, 4);
70862306a36Sopenharmony_ci		sg_init_table(desc.outfrags, 4);
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci		err = xdr_process_buf(buf, offset, cbcbytes, encryptor, &desc);
71162306a36Sopenharmony_ci		skcipher_request_zero(req);
71262306a36Sopenharmony_ci		if (err)
71362306a36Sopenharmony_ci			return err;
71462306a36Sopenharmony_ci	}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	/* Remaining plaintext is handled with CBC-CTS. */
71762306a36Sopenharmony_ci	err = gss_krb5_cts_crypt(cts_tfm, buf, offset + cbcbytes,
71862306a36Sopenharmony_ci				 desc.iv, pages, 1);
71962306a36Sopenharmony_ci	if (err)
72062306a36Sopenharmony_ci		return err;
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	if (unlikely(iv))
72362306a36Sopenharmony_ci		memcpy(iv, desc.iv, ivsize);
72462306a36Sopenharmony_ci	return 0;
72562306a36Sopenharmony_ci}
72662306a36Sopenharmony_ciEXPORT_SYMBOL_IF_KUNIT(krb5_cbc_cts_encrypt);
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci/**
72962306a36Sopenharmony_ci * krb5_cbc_cts_decrypt - decrypt in CBC mode with CTS
73062306a36Sopenharmony_ci * @cts_tfm: CBC cipher with CTS
73162306a36Sopenharmony_ci * @cbc_tfm: base CBC cipher
73262306a36Sopenharmony_ci * @offset: starting byte offset for plaintext
73362306a36Sopenharmony_ci * @buf: OUT: output buffer
73462306a36Sopenharmony_ci *
73562306a36Sopenharmony_ci * Return values:
73662306a36Sopenharmony_ci *   %0: decryption successful
73762306a36Sopenharmony_ci *   negative errno: decryption could not be completed
73862306a36Sopenharmony_ci */
73962306a36Sopenharmony_ciVISIBLE_IF_KUNIT
74062306a36Sopenharmony_ciint krb5_cbc_cts_decrypt(struct crypto_sync_skcipher *cts_tfm,
74162306a36Sopenharmony_ci			 struct crypto_sync_skcipher *cbc_tfm,
74262306a36Sopenharmony_ci			 u32 offset, struct xdr_buf *buf)
74362306a36Sopenharmony_ci{
74462306a36Sopenharmony_ci	u32 blocksize, nblocks, cbcbytes;
74562306a36Sopenharmony_ci	struct decryptor_desc desc;
74662306a36Sopenharmony_ci	int err;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	blocksize = crypto_sync_skcipher_blocksize(cts_tfm);
74962306a36Sopenharmony_ci	nblocks = (buf->len + blocksize - 1) / blocksize;
75062306a36Sopenharmony_ci	cbcbytes = 0;
75162306a36Sopenharmony_ci	if (nblocks > 2)
75262306a36Sopenharmony_ci		cbcbytes = (nblocks - 2) * blocksize;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	memset(desc.iv, 0, sizeof(desc.iv));
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	/* Handle block-sized chunks of plaintext with CBC. */
75762306a36Sopenharmony_ci	if (cbcbytes) {
75862306a36Sopenharmony_ci		SYNC_SKCIPHER_REQUEST_ON_STACK(req, cbc_tfm);
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci		desc.fragno = 0;
76162306a36Sopenharmony_ci		desc.fraglen = 0;
76262306a36Sopenharmony_ci		desc.req = req;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci		skcipher_request_set_sync_tfm(req, cbc_tfm);
76562306a36Sopenharmony_ci		skcipher_request_set_callback(req, 0, NULL, NULL);
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci		sg_init_table(desc.frags, 4);
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci		err = xdr_process_buf(buf, 0, cbcbytes, decryptor, &desc);
77062306a36Sopenharmony_ci		skcipher_request_zero(req);
77162306a36Sopenharmony_ci		if (err)
77262306a36Sopenharmony_ci			return err;
77362306a36Sopenharmony_ci	}
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	/* Remaining plaintext is handled with CBC-CTS. */
77662306a36Sopenharmony_ci	return gss_krb5_cts_crypt(cts_tfm, buf, cbcbytes, desc.iv, NULL, 0);
77762306a36Sopenharmony_ci}
77862306a36Sopenharmony_ciEXPORT_SYMBOL_IF_KUNIT(krb5_cbc_cts_decrypt);
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ciu32
78162306a36Sopenharmony_cigss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset,
78262306a36Sopenharmony_ci		     struct xdr_buf *buf, struct page **pages)
78362306a36Sopenharmony_ci{
78462306a36Sopenharmony_ci	u32 err;
78562306a36Sopenharmony_ci	struct xdr_netobj hmac;
78662306a36Sopenharmony_ci	u8 *ecptr;
78762306a36Sopenharmony_ci	struct crypto_sync_skcipher *cipher, *aux_cipher;
78862306a36Sopenharmony_ci	struct crypto_ahash *ahash;
78962306a36Sopenharmony_ci	struct page **save_pages;
79062306a36Sopenharmony_ci	unsigned int conflen;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	if (kctx->initiate) {
79362306a36Sopenharmony_ci		cipher = kctx->initiator_enc;
79462306a36Sopenharmony_ci		aux_cipher = kctx->initiator_enc_aux;
79562306a36Sopenharmony_ci		ahash = kctx->initiator_integ;
79662306a36Sopenharmony_ci	} else {
79762306a36Sopenharmony_ci		cipher = kctx->acceptor_enc;
79862306a36Sopenharmony_ci		aux_cipher = kctx->acceptor_enc_aux;
79962306a36Sopenharmony_ci		ahash = kctx->acceptor_integ;
80062306a36Sopenharmony_ci	}
80162306a36Sopenharmony_ci	conflen = crypto_sync_skcipher_blocksize(cipher);
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	/* hide the gss token header and insert the confounder */
80462306a36Sopenharmony_ci	offset += GSS_KRB5_TOK_HDR_LEN;
80562306a36Sopenharmony_ci	if (xdr_extend_head(buf, offset, conflen))
80662306a36Sopenharmony_ci		return GSS_S_FAILURE;
80762306a36Sopenharmony_ci	krb5_make_confounder(buf->head[0].iov_base + offset, conflen);
80862306a36Sopenharmony_ci	offset -= GSS_KRB5_TOK_HDR_LEN;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	if (buf->tail[0].iov_base != NULL) {
81162306a36Sopenharmony_ci		ecptr = buf->tail[0].iov_base + buf->tail[0].iov_len;
81262306a36Sopenharmony_ci	} else {
81362306a36Sopenharmony_ci		buf->tail[0].iov_base = buf->head[0].iov_base
81462306a36Sopenharmony_ci							+ buf->head[0].iov_len;
81562306a36Sopenharmony_ci		buf->tail[0].iov_len = 0;
81662306a36Sopenharmony_ci		ecptr = buf->tail[0].iov_base;
81762306a36Sopenharmony_ci	}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	/* copy plaintext gss token header after filler (if any) */
82062306a36Sopenharmony_ci	memcpy(ecptr, buf->head[0].iov_base + offset, GSS_KRB5_TOK_HDR_LEN);
82162306a36Sopenharmony_ci	buf->tail[0].iov_len += GSS_KRB5_TOK_HDR_LEN;
82262306a36Sopenharmony_ci	buf->len += GSS_KRB5_TOK_HDR_LEN;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci	hmac.len = kctx->gk5e->cksumlength;
82562306a36Sopenharmony_ci	hmac.data = buf->tail[0].iov_base + buf->tail[0].iov_len;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	/*
82862306a36Sopenharmony_ci	 * When we are called, pages points to the real page cache
82962306a36Sopenharmony_ci	 * data -- which we can't go and encrypt!  buf->pages points
83062306a36Sopenharmony_ci	 * to scratch pages which we are going to send off to the
83162306a36Sopenharmony_ci	 * client/server.  Swap in the plaintext pages to calculate
83262306a36Sopenharmony_ci	 * the hmac.
83362306a36Sopenharmony_ci	 */
83462306a36Sopenharmony_ci	save_pages = buf->pages;
83562306a36Sopenharmony_ci	buf->pages = pages;
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	err = gss_krb5_checksum(ahash, NULL, 0, buf,
83862306a36Sopenharmony_ci				offset + GSS_KRB5_TOK_HDR_LEN, &hmac);
83962306a36Sopenharmony_ci	buf->pages = save_pages;
84062306a36Sopenharmony_ci	if (err)
84162306a36Sopenharmony_ci		return GSS_S_FAILURE;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	err = krb5_cbc_cts_encrypt(cipher, aux_cipher,
84462306a36Sopenharmony_ci				   offset + GSS_KRB5_TOK_HDR_LEN,
84562306a36Sopenharmony_ci				   buf, pages, NULL, 0);
84662306a36Sopenharmony_ci	if (err)
84762306a36Sopenharmony_ci		return GSS_S_FAILURE;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	/* Now update buf to account for HMAC */
85062306a36Sopenharmony_ci	buf->tail[0].iov_len += kctx->gk5e->cksumlength;
85162306a36Sopenharmony_ci	buf->len += kctx->gk5e->cksumlength;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	return GSS_S_COMPLETE;
85462306a36Sopenharmony_ci}
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ciu32
85762306a36Sopenharmony_cigss_krb5_aes_decrypt(struct krb5_ctx *kctx, u32 offset, u32 len,
85862306a36Sopenharmony_ci		     struct xdr_buf *buf, u32 *headskip, u32 *tailskip)
85962306a36Sopenharmony_ci{
86062306a36Sopenharmony_ci	struct crypto_sync_skcipher *cipher, *aux_cipher;
86162306a36Sopenharmony_ci	struct crypto_ahash *ahash;
86262306a36Sopenharmony_ci	struct xdr_netobj our_hmac_obj;
86362306a36Sopenharmony_ci	u8 our_hmac[GSS_KRB5_MAX_CKSUM_LEN];
86462306a36Sopenharmony_ci	u8 pkt_hmac[GSS_KRB5_MAX_CKSUM_LEN];
86562306a36Sopenharmony_ci	struct xdr_buf subbuf;
86662306a36Sopenharmony_ci	u32 ret = 0;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	if (kctx->initiate) {
86962306a36Sopenharmony_ci		cipher = kctx->acceptor_enc;
87062306a36Sopenharmony_ci		aux_cipher = kctx->acceptor_enc_aux;
87162306a36Sopenharmony_ci		ahash = kctx->acceptor_integ;
87262306a36Sopenharmony_ci	} else {
87362306a36Sopenharmony_ci		cipher = kctx->initiator_enc;
87462306a36Sopenharmony_ci		aux_cipher = kctx->initiator_enc_aux;
87562306a36Sopenharmony_ci		ahash = kctx->initiator_integ;
87662306a36Sopenharmony_ci	}
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	/* create a segment skipping the header and leaving out the checksum */
87962306a36Sopenharmony_ci	xdr_buf_subsegment(buf, &subbuf, offset + GSS_KRB5_TOK_HDR_LEN,
88062306a36Sopenharmony_ci				    (len - offset - GSS_KRB5_TOK_HDR_LEN -
88162306a36Sopenharmony_ci				     kctx->gk5e->cksumlength));
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	ret = krb5_cbc_cts_decrypt(cipher, aux_cipher, 0, &subbuf);
88462306a36Sopenharmony_ci	if (ret)
88562306a36Sopenharmony_ci		goto out_err;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	our_hmac_obj.len = kctx->gk5e->cksumlength;
88862306a36Sopenharmony_ci	our_hmac_obj.data = our_hmac;
88962306a36Sopenharmony_ci	ret = gss_krb5_checksum(ahash, NULL, 0, &subbuf, 0, &our_hmac_obj);
89062306a36Sopenharmony_ci	if (ret)
89162306a36Sopenharmony_ci		goto out_err;
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	/* Get the packet's hmac value */
89462306a36Sopenharmony_ci	ret = read_bytes_from_xdr_buf(buf, len - kctx->gk5e->cksumlength,
89562306a36Sopenharmony_ci				      pkt_hmac, kctx->gk5e->cksumlength);
89662306a36Sopenharmony_ci	if (ret)
89762306a36Sopenharmony_ci		goto out_err;
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	if (crypto_memneq(pkt_hmac, our_hmac, kctx->gk5e->cksumlength) != 0) {
90062306a36Sopenharmony_ci		ret = GSS_S_BAD_SIG;
90162306a36Sopenharmony_ci		goto out_err;
90262306a36Sopenharmony_ci	}
90362306a36Sopenharmony_ci	*headskip = crypto_sync_skcipher_blocksize(cipher);
90462306a36Sopenharmony_ci	*tailskip = kctx->gk5e->cksumlength;
90562306a36Sopenharmony_ciout_err:
90662306a36Sopenharmony_ci	if (ret && ret != GSS_S_BAD_SIG)
90762306a36Sopenharmony_ci		ret = GSS_S_FAILURE;
90862306a36Sopenharmony_ci	return ret;
90962306a36Sopenharmony_ci}
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci/**
91262306a36Sopenharmony_ci * krb5_etm_checksum - Compute a MAC for a GSS Wrap token
91362306a36Sopenharmony_ci * @cipher: an initialized cipher transform
91462306a36Sopenharmony_ci * @tfm: an initialized hash transform
91562306a36Sopenharmony_ci * @body: xdr_buf containing an RPC message (body.len is the message length)
91662306a36Sopenharmony_ci * @body_offset: byte offset into @body to start checksumming
91762306a36Sopenharmony_ci * @cksumout: OUT: a buffer to be filled in with the computed HMAC
91862306a36Sopenharmony_ci *
91962306a36Sopenharmony_ci * Usually expressed as H = HMAC(K, IV | ciphertext)[1..h] .
92062306a36Sopenharmony_ci *
92162306a36Sopenharmony_ci * Caller provides the truncation length of the output token (h) in
92262306a36Sopenharmony_ci * cksumout.len.
92362306a36Sopenharmony_ci *
92462306a36Sopenharmony_ci * Return values:
92562306a36Sopenharmony_ci *   %GSS_S_COMPLETE: Digest computed, @cksumout filled in
92662306a36Sopenharmony_ci *   %GSS_S_FAILURE: Call failed
92762306a36Sopenharmony_ci */
92862306a36Sopenharmony_ciVISIBLE_IF_KUNIT
92962306a36Sopenharmony_ciu32 krb5_etm_checksum(struct crypto_sync_skcipher *cipher,
93062306a36Sopenharmony_ci		      struct crypto_ahash *tfm, const struct xdr_buf *body,
93162306a36Sopenharmony_ci		      int body_offset, struct xdr_netobj *cksumout)
93262306a36Sopenharmony_ci{
93362306a36Sopenharmony_ci	unsigned int ivsize = crypto_sync_skcipher_ivsize(cipher);
93462306a36Sopenharmony_ci	struct ahash_request *req;
93562306a36Sopenharmony_ci	struct scatterlist sg[1];
93662306a36Sopenharmony_ci	u8 *iv, *checksumdata;
93762306a36Sopenharmony_ci	int err = -ENOMEM;
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	checksumdata = kmalloc(crypto_ahash_digestsize(tfm), GFP_KERNEL);
94062306a36Sopenharmony_ci	if (!checksumdata)
94162306a36Sopenharmony_ci		return GSS_S_FAILURE;
94262306a36Sopenharmony_ci	/* For RPCSEC, the "initial cipher state" is always all zeroes. */
94362306a36Sopenharmony_ci	iv = kzalloc(ivsize, GFP_KERNEL);
94462306a36Sopenharmony_ci	if (!iv)
94562306a36Sopenharmony_ci		goto out_free_mem;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	req = ahash_request_alloc(tfm, GFP_KERNEL);
94862306a36Sopenharmony_ci	if (!req)
94962306a36Sopenharmony_ci		goto out_free_mem;
95062306a36Sopenharmony_ci	ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
95162306a36Sopenharmony_ci	err = crypto_ahash_init(req);
95262306a36Sopenharmony_ci	if (err)
95362306a36Sopenharmony_ci		goto out_free_ahash;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	sg_init_one(sg, iv, ivsize);
95662306a36Sopenharmony_ci	ahash_request_set_crypt(req, sg, NULL, ivsize);
95762306a36Sopenharmony_ci	err = crypto_ahash_update(req);
95862306a36Sopenharmony_ci	if (err)
95962306a36Sopenharmony_ci		goto out_free_ahash;
96062306a36Sopenharmony_ci	err = xdr_process_buf(body, body_offset, body->len - body_offset,
96162306a36Sopenharmony_ci			      checksummer, req);
96262306a36Sopenharmony_ci	if (err)
96362306a36Sopenharmony_ci		goto out_free_ahash;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	ahash_request_set_crypt(req, NULL, checksumdata, 0);
96662306a36Sopenharmony_ci	err = crypto_ahash_final(req);
96762306a36Sopenharmony_ci	if (err)
96862306a36Sopenharmony_ci		goto out_free_ahash;
96962306a36Sopenharmony_ci	memcpy(cksumout->data, checksumdata, cksumout->len);
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ciout_free_ahash:
97262306a36Sopenharmony_ci	ahash_request_free(req);
97362306a36Sopenharmony_ciout_free_mem:
97462306a36Sopenharmony_ci	kfree(iv);
97562306a36Sopenharmony_ci	kfree_sensitive(checksumdata);
97662306a36Sopenharmony_ci	return err ? GSS_S_FAILURE : GSS_S_COMPLETE;
97762306a36Sopenharmony_ci}
97862306a36Sopenharmony_ciEXPORT_SYMBOL_IF_KUNIT(krb5_etm_checksum);
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci/**
98162306a36Sopenharmony_ci * krb5_etm_encrypt - Encrypt using the RFC 8009 rules
98262306a36Sopenharmony_ci * @kctx: Kerberos context
98362306a36Sopenharmony_ci * @offset: starting offset of the payload, in bytes
98462306a36Sopenharmony_ci * @buf: OUT: send buffer to contain the encrypted payload
98562306a36Sopenharmony_ci * @pages: plaintext payload
98662306a36Sopenharmony_ci *
98762306a36Sopenharmony_ci * The main difference with aes_encrypt is that "The HMAC is
98862306a36Sopenharmony_ci * calculated over the cipher state concatenated with the AES
98962306a36Sopenharmony_ci * output, instead of being calculated over the confounder and
99062306a36Sopenharmony_ci * plaintext.  This allows the message receiver to verify the
99162306a36Sopenharmony_ci * integrity of the message before decrypting the message."
99262306a36Sopenharmony_ci *
99362306a36Sopenharmony_ci * RFC 8009 Section 5:
99462306a36Sopenharmony_ci *
99562306a36Sopenharmony_ci * encryption function: as follows, where E() is AES encryption in
99662306a36Sopenharmony_ci * CBC-CS3 mode, and h is the size of truncated HMAC (128 bits or
99762306a36Sopenharmony_ci * 192 bits as described above).
99862306a36Sopenharmony_ci *
99962306a36Sopenharmony_ci *    N = random value of length 128 bits (the AES block size)
100062306a36Sopenharmony_ci *    IV = cipher state
100162306a36Sopenharmony_ci *    C = E(Ke, N | plaintext, IV)
100262306a36Sopenharmony_ci *    H = HMAC(Ki, IV | C)
100362306a36Sopenharmony_ci *    ciphertext = C | H[1..h]
100462306a36Sopenharmony_ci *
100562306a36Sopenharmony_ci * This encryption formula provides AEAD EtM with key separation.
100662306a36Sopenharmony_ci *
100762306a36Sopenharmony_ci * Return values:
100862306a36Sopenharmony_ci *   %GSS_S_COMPLETE: Encryption successful
100962306a36Sopenharmony_ci *   %GSS_S_FAILURE: Encryption failed
101062306a36Sopenharmony_ci */
101162306a36Sopenharmony_ciu32
101262306a36Sopenharmony_cikrb5_etm_encrypt(struct krb5_ctx *kctx, u32 offset,
101362306a36Sopenharmony_ci		 struct xdr_buf *buf, struct page **pages)
101462306a36Sopenharmony_ci{
101562306a36Sopenharmony_ci	struct crypto_sync_skcipher *cipher, *aux_cipher;
101662306a36Sopenharmony_ci	struct crypto_ahash *ahash;
101762306a36Sopenharmony_ci	struct xdr_netobj hmac;
101862306a36Sopenharmony_ci	unsigned int conflen;
101962306a36Sopenharmony_ci	u8 *ecptr;
102062306a36Sopenharmony_ci	u32 err;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	if (kctx->initiate) {
102362306a36Sopenharmony_ci		cipher = kctx->initiator_enc;
102462306a36Sopenharmony_ci		aux_cipher = kctx->initiator_enc_aux;
102562306a36Sopenharmony_ci		ahash = kctx->initiator_integ;
102662306a36Sopenharmony_ci	} else {
102762306a36Sopenharmony_ci		cipher = kctx->acceptor_enc;
102862306a36Sopenharmony_ci		aux_cipher = kctx->acceptor_enc_aux;
102962306a36Sopenharmony_ci		ahash = kctx->acceptor_integ;
103062306a36Sopenharmony_ci	}
103162306a36Sopenharmony_ci	conflen = crypto_sync_skcipher_blocksize(cipher);
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	offset += GSS_KRB5_TOK_HDR_LEN;
103462306a36Sopenharmony_ci	if (xdr_extend_head(buf, offset, conflen))
103562306a36Sopenharmony_ci		return GSS_S_FAILURE;
103662306a36Sopenharmony_ci	krb5_make_confounder(buf->head[0].iov_base + offset, conflen);
103762306a36Sopenharmony_ci	offset -= GSS_KRB5_TOK_HDR_LEN;
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	if (buf->tail[0].iov_base) {
104062306a36Sopenharmony_ci		ecptr = buf->tail[0].iov_base + buf->tail[0].iov_len;
104162306a36Sopenharmony_ci	} else {
104262306a36Sopenharmony_ci		buf->tail[0].iov_base = buf->head[0].iov_base
104362306a36Sopenharmony_ci							+ buf->head[0].iov_len;
104462306a36Sopenharmony_ci		buf->tail[0].iov_len = 0;
104562306a36Sopenharmony_ci		ecptr = buf->tail[0].iov_base;
104662306a36Sopenharmony_ci	}
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	memcpy(ecptr, buf->head[0].iov_base + offset, GSS_KRB5_TOK_HDR_LEN);
104962306a36Sopenharmony_ci	buf->tail[0].iov_len += GSS_KRB5_TOK_HDR_LEN;
105062306a36Sopenharmony_ci	buf->len += GSS_KRB5_TOK_HDR_LEN;
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	err = krb5_cbc_cts_encrypt(cipher, aux_cipher,
105362306a36Sopenharmony_ci				   offset + GSS_KRB5_TOK_HDR_LEN,
105462306a36Sopenharmony_ci				   buf, pages, NULL, 0);
105562306a36Sopenharmony_ci	if (err)
105662306a36Sopenharmony_ci		return GSS_S_FAILURE;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	hmac.data = buf->tail[0].iov_base + buf->tail[0].iov_len;
105962306a36Sopenharmony_ci	hmac.len = kctx->gk5e->cksumlength;
106062306a36Sopenharmony_ci	err = krb5_etm_checksum(cipher, ahash,
106162306a36Sopenharmony_ci				buf, offset + GSS_KRB5_TOK_HDR_LEN, &hmac);
106262306a36Sopenharmony_ci	if (err)
106362306a36Sopenharmony_ci		goto out_err;
106462306a36Sopenharmony_ci	buf->tail[0].iov_len += kctx->gk5e->cksumlength;
106562306a36Sopenharmony_ci	buf->len += kctx->gk5e->cksumlength;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	return GSS_S_COMPLETE;
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ciout_err:
107062306a36Sopenharmony_ci	return GSS_S_FAILURE;
107162306a36Sopenharmony_ci}
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci/**
107462306a36Sopenharmony_ci * krb5_etm_decrypt - Decrypt using the RFC 8009 rules
107562306a36Sopenharmony_ci * @kctx: Kerberos context
107662306a36Sopenharmony_ci * @offset: starting offset of the ciphertext, in bytes
107762306a36Sopenharmony_ci * @len:
107862306a36Sopenharmony_ci * @buf:
107962306a36Sopenharmony_ci * @headskip: OUT: the enctype's confounder length, in octets
108062306a36Sopenharmony_ci * @tailskip: OUT: the enctype's HMAC length, in octets
108162306a36Sopenharmony_ci *
108262306a36Sopenharmony_ci * RFC 8009 Section 5:
108362306a36Sopenharmony_ci *
108462306a36Sopenharmony_ci * decryption function: as follows, where D() is AES decryption in
108562306a36Sopenharmony_ci * CBC-CS3 mode, and h is the size of truncated HMAC.
108662306a36Sopenharmony_ci *
108762306a36Sopenharmony_ci *    (C, H) = ciphertext
108862306a36Sopenharmony_ci *        (Note: H is the last h bits of the ciphertext.)
108962306a36Sopenharmony_ci *    IV = cipher state
109062306a36Sopenharmony_ci *    if H != HMAC(Ki, IV | C)[1..h]
109162306a36Sopenharmony_ci *        stop, report error
109262306a36Sopenharmony_ci *    (N, P) = D(Ke, C, IV)
109362306a36Sopenharmony_ci *
109462306a36Sopenharmony_ci * Return values:
109562306a36Sopenharmony_ci *   %GSS_S_COMPLETE: Decryption successful
109662306a36Sopenharmony_ci *   %GSS_S_BAD_SIG: computed HMAC != received HMAC
109762306a36Sopenharmony_ci *   %GSS_S_FAILURE: Decryption failed
109862306a36Sopenharmony_ci */
109962306a36Sopenharmony_ciu32
110062306a36Sopenharmony_cikrb5_etm_decrypt(struct krb5_ctx *kctx, u32 offset, u32 len,
110162306a36Sopenharmony_ci		 struct xdr_buf *buf, u32 *headskip, u32 *tailskip)
110262306a36Sopenharmony_ci{
110362306a36Sopenharmony_ci	struct crypto_sync_skcipher *cipher, *aux_cipher;
110462306a36Sopenharmony_ci	u8 our_hmac[GSS_KRB5_MAX_CKSUM_LEN];
110562306a36Sopenharmony_ci	u8 pkt_hmac[GSS_KRB5_MAX_CKSUM_LEN];
110662306a36Sopenharmony_ci	struct xdr_netobj our_hmac_obj;
110762306a36Sopenharmony_ci	struct crypto_ahash *ahash;
110862306a36Sopenharmony_ci	struct xdr_buf subbuf;
110962306a36Sopenharmony_ci	u32 ret = 0;
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	if (kctx->initiate) {
111262306a36Sopenharmony_ci		cipher = kctx->acceptor_enc;
111362306a36Sopenharmony_ci		aux_cipher = kctx->acceptor_enc_aux;
111462306a36Sopenharmony_ci		ahash = kctx->acceptor_integ;
111562306a36Sopenharmony_ci	} else {
111662306a36Sopenharmony_ci		cipher = kctx->initiator_enc;
111762306a36Sopenharmony_ci		aux_cipher = kctx->initiator_enc_aux;
111862306a36Sopenharmony_ci		ahash = kctx->initiator_integ;
111962306a36Sopenharmony_ci	}
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	/* Extract the ciphertext into @subbuf. */
112262306a36Sopenharmony_ci	xdr_buf_subsegment(buf, &subbuf, offset + GSS_KRB5_TOK_HDR_LEN,
112362306a36Sopenharmony_ci			   (len - offset - GSS_KRB5_TOK_HDR_LEN -
112462306a36Sopenharmony_ci			    kctx->gk5e->cksumlength));
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	our_hmac_obj.data = our_hmac;
112762306a36Sopenharmony_ci	our_hmac_obj.len = kctx->gk5e->cksumlength;
112862306a36Sopenharmony_ci	ret = krb5_etm_checksum(cipher, ahash, &subbuf, 0, &our_hmac_obj);
112962306a36Sopenharmony_ci	if (ret)
113062306a36Sopenharmony_ci		goto out_err;
113162306a36Sopenharmony_ci	ret = read_bytes_from_xdr_buf(buf, len - kctx->gk5e->cksumlength,
113262306a36Sopenharmony_ci				      pkt_hmac, kctx->gk5e->cksumlength);
113362306a36Sopenharmony_ci	if (ret)
113462306a36Sopenharmony_ci		goto out_err;
113562306a36Sopenharmony_ci	if (crypto_memneq(pkt_hmac, our_hmac, kctx->gk5e->cksumlength) != 0) {
113662306a36Sopenharmony_ci		ret = GSS_S_BAD_SIG;
113762306a36Sopenharmony_ci		goto out_err;
113862306a36Sopenharmony_ci	}
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	ret = krb5_cbc_cts_decrypt(cipher, aux_cipher, 0, &subbuf);
114162306a36Sopenharmony_ci	if (ret) {
114262306a36Sopenharmony_ci		ret = GSS_S_FAILURE;
114362306a36Sopenharmony_ci		goto out_err;
114462306a36Sopenharmony_ci	}
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	*headskip = crypto_sync_skcipher_blocksize(cipher);
114762306a36Sopenharmony_ci	*tailskip = kctx->gk5e->cksumlength;
114862306a36Sopenharmony_ci	return GSS_S_COMPLETE;
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ciout_err:
115162306a36Sopenharmony_ci	if (ret != GSS_S_BAD_SIG)
115262306a36Sopenharmony_ci		ret = GSS_S_FAILURE;
115362306a36Sopenharmony_ci	return ret;
115462306a36Sopenharmony_ci}
1155