18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci *  linux/net/sunrpc/gss_krb5_crypto.c
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci *  Copyright (c) 2000-2008 The Regents of the University of Michigan.
58c2ecf20Sopenharmony_ci *  All rights reserved.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *  Andy Adamson   <andros@umich.edu>
88c2ecf20Sopenharmony_ci *  Bruce Fields   <bfields@umich.edu>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci/*
128c2ecf20Sopenharmony_ci * Copyright (C) 1998 by the FundsXpress, INC.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * All rights reserved.
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * Export of this software from the United States of America may require
178c2ecf20Sopenharmony_ci * a specific license from the United States Government.  It is the
188c2ecf20Sopenharmony_ci * responsibility of any person or organization contemplating export to
198c2ecf20Sopenharmony_ci * obtain such a license before exporting.
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
228c2ecf20Sopenharmony_ci * distribute this software and its documentation for any purpose and
238c2ecf20Sopenharmony_ci * without fee is hereby granted, provided that the above copyright
248c2ecf20Sopenharmony_ci * notice appear in all copies and that both that copyright notice and
258c2ecf20Sopenharmony_ci * this permission notice appear in supporting documentation, and that
268c2ecf20Sopenharmony_ci * the name of FundsXpress. not be used in advertising or publicity pertaining
278c2ecf20Sopenharmony_ci * to distribution of the software without specific, written prior
288c2ecf20Sopenharmony_ci * permission.  FundsXpress makes no representations about the suitability of
298c2ecf20Sopenharmony_ci * this software for any purpose.  It is provided "as is" without express
308c2ecf20Sopenharmony_ci * or implied warranty.
318c2ecf20Sopenharmony_ci *
328c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
338c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
348c2ecf20Sopenharmony_ci * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#include <crypto/algapi.h>
388c2ecf20Sopenharmony_ci#include <crypto/hash.h>
398c2ecf20Sopenharmony_ci#include <crypto/skcipher.h>
408c2ecf20Sopenharmony_ci#include <linux/err.h>
418c2ecf20Sopenharmony_ci#include <linux/types.h>
428c2ecf20Sopenharmony_ci#include <linux/mm.h>
438c2ecf20Sopenharmony_ci#include <linux/scatterlist.h>
448c2ecf20Sopenharmony_ci#include <linux/highmem.h>
458c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
468c2ecf20Sopenharmony_ci#include <linux/random.h>
478c2ecf20Sopenharmony_ci#include <linux/sunrpc/gss_krb5.h>
488c2ecf20Sopenharmony_ci#include <linux/sunrpc/xdr.h>
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
518c2ecf20Sopenharmony_ci# define RPCDBG_FACILITY        RPCDBG_AUTH
528c2ecf20Sopenharmony_ci#endif
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ciu32
558c2ecf20Sopenharmony_cikrb5_encrypt(
568c2ecf20Sopenharmony_ci	struct crypto_sync_skcipher *tfm,
578c2ecf20Sopenharmony_ci	void * iv,
588c2ecf20Sopenharmony_ci	void * in,
598c2ecf20Sopenharmony_ci	void * out,
608c2ecf20Sopenharmony_ci	int length)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	u32 ret = -EINVAL;
638c2ecf20Sopenharmony_ci	struct scatterlist sg[1];
648c2ecf20Sopenharmony_ci	u8 local_iv[GSS_KRB5_MAX_BLOCKSIZE] = {0};
658c2ecf20Sopenharmony_ci	SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	if (length % crypto_sync_skcipher_blocksize(tfm) != 0)
688c2ecf20Sopenharmony_ci		goto out;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	if (crypto_sync_skcipher_ivsize(tfm) > GSS_KRB5_MAX_BLOCKSIZE) {
718c2ecf20Sopenharmony_ci		dprintk("RPC:       gss_k5encrypt: tfm iv size too large %d\n",
728c2ecf20Sopenharmony_ci			crypto_sync_skcipher_ivsize(tfm));
738c2ecf20Sopenharmony_ci		goto out;
748c2ecf20Sopenharmony_ci	}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	if (iv)
778c2ecf20Sopenharmony_ci		memcpy(local_iv, iv, crypto_sync_skcipher_ivsize(tfm));
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	memcpy(out, in, length);
808c2ecf20Sopenharmony_ci	sg_init_one(sg, out, length);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	skcipher_request_set_sync_tfm(req, tfm);
838c2ecf20Sopenharmony_ci	skcipher_request_set_callback(req, 0, NULL, NULL);
848c2ecf20Sopenharmony_ci	skcipher_request_set_crypt(req, sg, sg, length, local_iv);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	ret = crypto_skcipher_encrypt(req);
878c2ecf20Sopenharmony_ci	skcipher_request_zero(req);
888c2ecf20Sopenharmony_ciout:
898c2ecf20Sopenharmony_ci	dprintk("RPC:       krb5_encrypt returns %d\n", ret);
908c2ecf20Sopenharmony_ci	return ret;
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ciu32
948c2ecf20Sopenharmony_cikrb5_decrypt(
958c2ecf20Sopenharmony_ci     struct crypto_sync_skcipher *tfm,
968c2ecf20Sopenharmony_ci     void * iv,
978c2ecf20Sopenharmony_ci     void * in,
988c2ecf20Sopenharmony_ci     void * out,
998c2ecf20Sopenharmony_ci     int length)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	u32 ret = -EINVAL;
1028c2ecf20Sopenharmony_ci	struct scatterlist sg[1];
1038c2ecf20Sopenharmony_ci	u8 local_iv[GSS_KRB5_MAX_BLOCKSIZE] = {0};
1048c2ecf20Sopenharmony_ci	SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	if (length % crypto_sync_skcipher_blocksize(tfm) != 0)
1078c2ecf20Sopenharmony_ci		goto out;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	if (crypto_sync_skcipher_ivsize(tfm) > GSS_KRB5_MAX_BLOCKSIZE) {
1108c2ecf20Sopenharmony_ci		dprintk("RPC:       gss_k5decrypt: tfm iv size too large %d\n",
1118c2ecf20Sopenharmony_ci			crypto_sync_skcipher_ivsize(tfm));
1128c2ecf20Sopenharmony_ci		goto out;
1138c2ecf20Sopenharmony_ci	}
1148c2ecf20Sopenharmony_ci	if (iv)
1158c2ecf20Sopenharmony_ci		memcpy(local_iv, iv, crypto_sync_skcipher_ivsize(tfm));
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	memcpy(out, in, length);
1188c2ecf20Sopenharmony_ci	sg_init_one(sg, out, length);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	skcipher_request_set_sync_tfm(req, tfm);
1218c2ecf20Sopenharmony_ci	skcipher_request_set_callback(req, 0, NULL, NULL);
1228c2ecf20Sopenharmony_ci	skcipher_request_set_crypt(req, sg, sg, length, local_iv);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	ret = crypto_skcipher_decrypt(req);
1258c2ecf20Sopenharmony_ci	skcipher_request_zero(req);
1268c2ecf20Sopenharmony_ciout:
1278c2ecf20Sopenharmony_ci	dprintk("RPC:       gss_k5decrypt returns %d\n",ret);
1288c2ecf20Sopenharmony_ci	return ret;
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic int
1328c2ecf20Sopenharmony_cichecksummer(struct scatterlist *sg, void *data)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	struct ahash_request *req = data;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	ahash_request_set_crypt(req, sg, NULL, sg->length);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	return crypto_ahash_update(req);
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci/*
1428c2ecf20Sopenharmony_ci * checksum the plaintext data and hdrlen bytes of the token header
1438c2ecf20Sopenharmony_ci * The checksum is performed over the first 8 bytes of the
1448c2ecf20Sopenharmony_ci * gss token header and then over the data body
1458c2ecf20Sopenharmony_ci */
1468c2ecf20Sopenharmony_ciu32
1478c2ecf20Sopenharmony_cimake_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
1488c2ecf20Sopenharmony_ci	      struct xdr_buf *body, int body_offset, u8 *cksumkey,
1498c2ecf20Sopenharmony_ci	      unsigned int usage, struct xdr_netobj *cksumout)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	struct crypto_ahash *tfm;
1528c2ecf20Sopenharmony_ci	struct ahash_request *req;
1538c2ecf20Sopenharmony_ci	struct scatterlist              sg[1];
1548c2ecf20Sopenharmony_ci	int err = -1;
1558c2ecf20Sopenharmony_ci	u8 *checksumdata;
1568c2ecf20Sopenharmony_ci	unsigned int checksumlen;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	if (cksumout->len < kctx->gk5e->cksumlength) {
1598c2ecf20Sopenharmony_ci		dprintk("%s: checksum buffer length, %u, too small for %s\n",
1608c2ecf20Sopenharmony_ci			__func__, cksumout->len, kctx->gk5e->name);
1618c2ecf20Sopenharmony_ci		return GSS_S_FAILURE;
1628c2ecf20Sopenharmony_ci	}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	checksumdata = kmalloc(GSS_KRB5_MAX_CKSUM_LEN, GFP_NOFS);
1658c2ecf20Sopenharmony_ci	if (checksumdata == NULL)
1668c2ecf20Sopenharmony_ci		return GSS_S_FAILURE;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	tfm = crypto_alloc_ahash(kctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC);
1698c2ecf20Sopenharmony_ci	if (IS_ERR(tfm))
1708c2ecf20Sopenharmony_ci		goto out_free_cksum;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	req = ahash_request_alloc(tfm, GFP_NOFS);
1738c2ecf20Sopenharmony_ci	if (!req)
1748c2ecf20Sopenharmony_ci		goto out_free_ahash;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	checksumlen = crypto_ahash_digestsize(tfm);
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	if (cksumkey != NULL) {
1818c2ecf20Sopenharmony_ci		err = crypto_ahash_setkey(tfm, cksumkey,
1828c2ecf20Sopenharmony_ci					  kctx->gk5e->keylength);
1838c2ecf20Sopenharmony_ci		if (err)
1848c2ecf20Sopenharmony_ci			goto out;
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	err = crypto_ahash_init(req);
1888c2ecf20Sopenharmony_ci	if (err)
1898c2ecf20Sopenharmony_ci		goto out;
1908c2ecf20Sopenharmony_ci	sg_init_one(sg, header, hdrlen);
1918c2ecf20Sopenharmony_ci	ahash_request_set_crypt(req, sg, NULL, hdrlen);
1928c2ecf20Sopenharmony_ci	err = crypto_ahash_update(req);
1938c2ecf20Sopenharmony_ci	if (err)
1948c2ecf20Sopenharmony_ci		goto out;
1958c2ecf20Sopenharmony_ci	err = xdr_process_buf(body, body_offset, body->len - body_offset,
1968c2ecf20Sopenharmony_ci			      checksummer, req);
1978c2ecf20Sopenharmony_ci	if (err)
1988c2ecf20Sopenharmony_ci		goto out;
1998c2ecf20Sopenharmony_ci	ahash_request_set_crypt(req, NULL, checksumdata, 0);
2008c2ecf20Sopenharmony_ci	err = crypto_ahash_final(req);
2018c2ecf20Sopenharmony_ci	if (err)
2028c2ecf20Sopenharmony_ci		goto out;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	switch (kctx->gk5e->ctype) {
2058c2ecf20Sopenharmony_ci	case CKSUMTYPE_RSA_MD5:
2068c2ecf20Sopenharmony_ci		err = kctx->gk5e->encrypt(kctx->seq, NULL, checksumdata,
2078c2ecf20Sopenharmony_ci					  checksumdata, checksumlen);
2088c2ecf20Sopenharmony_ci		if (err)
2098c2ecf20Sopenharmony_ci			goto out;
2108c2ecf20Sopenharmony_ci		memcpy(cksumout->data,
2118c2ecf20Sopenharmony_ci		       checksumdata + checksumlen - kctx->gk5e->cksumlength,
2128c2ecf20Sopenharmony_ci		       kctx->gk5e->cksumlength);
2138c2ecf20Sopenharmony_ci		break;
2148c2ecf20Sopenharmony_ci	case CKSUMTYPE_HMAC_SHA1_DES3:
2158c2ecf20Sopenharmony_ci		memcpy(cksumout->data, checksumdata, kctx->gk5e->cksumlength);
2168c2ecf20Sopenharmony_ci		break;
2178c2ecf20Sopenharmony_ci	default:
2188c2ecf20Sopenharmony_ci		BUG();
2198c2ecf20Sopenharmony_ci		break;
2208c2ecf20Sopenharmony_ci	}
2218c2ecf20Sopenharmony_ci	cksumout->len = kctx->gk5e->cksumlength;
2228c2ecf20Sopenharmony_ciout:
2238c2ecf20Sopenharmony_ci	ahash_request_free(req);
2248c2ecf20Sopenharmony_ciout_free_ahash:
2258c2ecf20Sopenharmony_ci	crypto_free_ahash(tfm);
2268c2ecf20Sopenharmony_ciout_free_cksum:
2278c2ecf20Sopenharmony_ci	kfree(checksumdata);
2288c2ecf20Sopenharmony_ci	return err ? GSS_S_FAILURE : 0;
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci/*
2328c2ecf20Sopenharmony_ci * checksum the plaintext data and hdrlen bytes of the token header
2338c2ecf20Sopenharmony_ci * Per rfc4121, sec. 4.2.4, the checksum is performed over the data
2348c2ecf20Sopenharmony_ci * body then over the first 16 octets of the MIC token
2358c2ecf20Sopenharmony_ci * Inclusion of the header data in the calculation of the
2368c2ecf20Sopenharmony_ci * checksum is optional.
2378c2ecf20Sopenharmony_ci */
2388c2ecf20Sopenharmony_ciu32
2398c2ecf20Sopenharmony_cimake_checksum_v2(struct krb5_ctx *kctx, char *header, int hdrlen,
2408c2ecf20Sopenharmony_ci		 struct xdr_buf *body, int body_offset, u8 *cksumkey,
2418c2ecf20Sopenharmony_ci		 unsigned int usage, struct xdr_netobj *cksumout)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	struct crypto_ahash *tfm;
2448c2ecf20Sopenharmony_ci	struct ahash_request *req;
2458c2ecf20Sopenharmony_ci	struct scatterlist sg[1];
2468c2ecf20Sopenharmony_ci	int err = -1;
2478c2ecf20Sopenharmony_ci	u8 *checksumdata;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	if (kctx->gk5e->keyed_cksum == 0) {
2508c2ecf20Sopenharmony_ci		dprintk("%s: expected keyed hash for %s\n",
2518c2ecf20Sopenharmony_ci			__func__, kctx->gk5e->name);
2528c2ecf20Sopenharmony_ci		return GSS_S_FAILURE;
2538c2ecf20Sopenharmony_ci	}
2548c2ecf20Sopenharmony_ci	if (cksumkey == NULL) {
2558c2ecf20Sopenharmony_ci		dprintk("%s: no key supplied for %s\n",
2568c2ecf20Sopenharmony_ci			__func__, kctx->gk5e->name);
2578c2ecf20Sopenharmony_ci		return GSS_S_FAILURE;
2588c2ecf20Sopenharmony_ci	}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	checksumdata = kmalloc(GSS_KRB5_MAX_CKSUM_LEN, GFP_NOFS);
2618c2ecf20Sopenharmony_ci	if (!checksumdata)
2628c2ecf20Sopenharmony_ci		return GSS_S_FAILURE;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	tfm = crypto_alloc_ahash(kctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC);
2658c2ecf20Sopenharmony_ci	if (IS_ERR(tfm))
2668c2ecf20Sopenharmony_ci		goto out_free_cksum;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	req = ahash_request_alloc(tfm, GFP_NOFS);
2698c2ecf20Sopenharmony_ci	if (!req)
2708c2ecf20Sopenharmony_ci		goto out_free_ahash;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	err = crypto_ahash_setkey(tfm, cksumkey, kctx->gk5e->keylength);
2758c2ecf20Sopenharmony_ci	if (err)
2768c2ecf20Sopenharmony_ci		goto out;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	err = crypto_ahash_init(req);
2798c2ecf20Sopenharmony_ci	if (err)
2808c2ecf20Sopenharmony_ci		goto out;
2818c2ecf20Sopenharmony_ci	err = xdr_process_buf(body, body_offset, body->len - body_offset,
2828c2ecf20Sopenharmony_ci			      checksummer, req);
2838c2ecf20Sopenharmony_ci	if (err)
2848c2ecf20Sopenharmony_ci		goto out;
2858c2ecf20Sopenharmony_ci	if (header != NULL) {
2868c2ecf20Sopenharmony_ci		sg_init_one(sg, header, hdrlen);
2878c2ecf20Sopenharmony_ci		ahash_request_set_crypt(req, sg, NULL, hdrlen);
2888c2ecf20Sopenharmony_ci		err = crypto_ahash_update(req);
2898c2ecf20Sopenharmony_ci		if (err)
2908c2ecf20Sopenharmony_ci			goto out;
2918c2ecf20Sopenharmony_ci	}
2928c2ecf20Sopenharmony_ci	ahash_request_set_crypt(req, NULL, checksumdata, 0);
2938c2ecf20Sopenharmony_ci	err = crypto_ahash_final(req);
2948c2ecf20Sopenharmony_ci	if (err)
2958c2ecf20Sopenharmony_ci		goto out;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	cksumout->len = kctx->gk5e->cksumlength;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	switch (kctx->gk5e->ctype) {
3008c2ecf20Sopenharmony_ci	case CKSUMTYPE_HMAC_SHA1_96_AES128:
3018c2ecf20Sopenharmony_ci	case CKSUMTYPE_HMAC_SHA1_96_AES256:
3028c2ecf20Sopenharmony_ci		/* note that this truncates the hash */
3038c2ecf20Sopenharmony_ci		memcpy(cksumout->data, checksumdata, kctx->gk5e->cksumlength);
3048c2ecf20Sopenharmony_ci		break;
3058c2ecf20Sopenharmony_ci	default:
3068c2ecf20Sopenharmony_ci		BUG();
3078c2ecf20Sopenharmony_ci		break;
3088c2ecf20Sopenharmony_ci	}
3098c2ecf20Sopenharmony_ciout:
3108c2ecf20Sopenharmony_ci	ahash_request_free(req);
3118c2ecf20Sopenharmony_ciout_free_ahash:
3128c2ecf20Sopenharmony_ci	crypto_free_ahash(tfm);
3138c2ecf20Sopenharmony_ciout_free_cksum:
3148c2ecf20Sopenharmony_ci	kfree(checksumdata);
3158c2ecf20Sopenharmony_ci	return err ? GSS_S_FAILURE : 0;
3168c2ecf20Sopenharmony_ci}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_cistruct encryptor_desc {
3198c2ecf20Sopenharmony_ci	u8 iv[GSS_KRB5_MAX_BLOCKSIZE];
3208c2ecf20Sopenharmony_ci	struct skcipher_request *req;
3218c2ecf20Sopenharmony_ci	int pos;
3228c2ecf20Sopenharmony_ci	struct xdr_buf *outbuf;
3238c2ecf20Sopenharmony_ci	struct page **pages;
3248c2ecf20Sopenharmony_ci	struct scatterlist infrags[4];
3258c2ecf20Sopenharmony_ci	struct scatterlist outfrags[4];
3268c2ecf20Sopenharmony_ci	int fragno;
3278c2ecf20Sopenharmony_ci	int fraglen;
3288c2ecf20Sopenharmony_ci};
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_cistatic int
3318c2ecf20Sopenharmony_ciencryptor(struct scatterlist *sg, void *data)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	struct encryptor_desc *desc = data;
3348c2ecf20Sopenharmony_ci	struct xdr_buf *outbuf = desc->outbuf;
3358c2ecf20Sopenharmony_ci	struct crypto_sync_skcipher *tfm =
3368c2ecf20Sopenharmony_ci		crypto_sync_skcipher_reqtfm(desc->req);
3378c2ecf20Sopenharmony_ci	struct page *in_page;
3388c2ecf20Sopenharmony_ci	int thislen = desc->fraglen + sg->length;
3398c2ecf20Sopenharmony_ci	int fraglen, ret;
3408c2ecf20Sopenharmony_ci	int page_pos;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	/* Worst case is 4 fragments: head, end of page 1, start
3438c2ecf20Sopenharmony_ci	 * of page 2, tail.  Anything more is a bug. */
3448c2ecf20Sopenharmony_ci	BUG_ON(desc->fragno > 3);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	page_pos = desc->pos - outbuf->head[0].iov_len;
3478c2ecf20Sopenharmony_ci	if (page_pos >= 0 && page_pos < outbuf->page_len) {
3488c2ecf20Sopenharmony_ci		/* pages are not in place: */
3498c2ecf20Sopenharmony_ci		int i = (page_pos + outbuf->page_base) >> PAGE_SHIFT;
3508c2ecf20Sopenharmony_ci		in_page = desc->pages[i];
3518c2ecf20Sopenharmony_ci	} else {
3528c2ecf20Sopenharmony_ci		in_page = sg_page(sg);
3538c2ecf20Sopenharmony_ci	}
3548c2ecf20Sopenharmony_ci	sg_set_page(&desc->infrags[desc->fragno], in_page, sg->length,
3558c2ecf20Sopenharmony_ci		    sg->offset);
3568c2ecf20Sopenharmony_ci	sg_set_page(&desc->outfrags[desc->fragno], sg_page(sg), sg->length,
3578c2ecf20Sopenharmony_ci		    sg->offset);
3588c2ecf20Sopenharmony_ci	desc->fragno++;
3598c2ecf20Sopenharmony_ci	desc->fraglen += sg->length;
3608c2ecf20Sopenharmony_ci	desc->pos += sg->length;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	fraglen = thislen & (crypto_sync_skcipher_blocksize(tfm) - 1);
3638c2ecf20Sopenharmony_ci	thislen -= fraglen;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	if (thislen == 0)
3668c2ecf20Sopenharmony_ci		return 0;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	sg_mark_end(&desc->infrags[desc->fragno - 1]);
3698c2ecf20Sopenharmony_ci	sg_mark_end(&desc->outfrags[desc->fragno - 1]);
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	skcipher_request_set_crypt(desc->req, desc->infrags, desc->outfrags,
3728c2ecf20Sopenharmony_ci				   thislen, desc->iv);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	ret = crypto_skcipher_encrypt(desc->req);
3758c2ecf20Sopenharmony_ci	if (ret)
3768c2ecf20Sopenharmony_ci		return ret;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	sg_init_table(desc->infrags, 4);
3798c2ecf20Sopenharmony_ci	sg_init_table(desc->outfrags, 4);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	if (fraglen) {
3828c2ecf20Sopenharmony_ci		sg_set_page(&desc->outfrags[0], sg_page(sg), fraglen,
3838c2ecf20Sopenharmony_ci				sg->offset + sg->length - fraglen);
3848c2ecf20Sopenharmony_ci		desc->infrags[0] = desc->outfrags[0];
3858c2ecf20Sopenharmony_ci		sg_assign_page(&desc->infrags[0], in_page);
3868c2ecf20Sopenharmony_ci		desc->fragno = 1;
3878c2ecf20Sopenharmony_ci		desc->fraglen = fraglen;
3888c2ecf20Sopenharmony_ci	} else {
3898c2ecf20Sopenharmony_ci		desc->fragno = 0;
3908c2ecf20Sopenharmony_ci		desc->fraglen = 0;
3918c2ecf20Sopenharmony_ci	}
3928c2ecf20Sopenharmony_ci	return 0;
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ciint
3968c2ecf20Sopenharmony_cigss_encrypt_xdr_buf(struct crypto_sync_skcipher *tfm, struct xdr_buf *buf,
3978c2ecf20Sopenharmony_ci		    int offset, struct page **pages)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	int ret;
4008c2ecf20Sopenharmony_ci	struct encryptor_desc desc;
4018c2ecf20Sopenharmony_ci	SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	BUG_ON((buf->len - offset) % crypto_sync_skcipher_blocksize(tfm) != 0);
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	skcipher_request_set_sync_tfm(req, tfm);
4068c2ecf20Sopenharmony_ci	skcipher_request_set_callback(req, 0, NULL, NULL);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	memset(desc.iv, 0, sizeof(desc.iv));
4098c2ecf20Sopenharmony_ci	desc.req = req;
4108c2ecf20Sopenharmony_ci	desc.pos = offset;
4118c2ecf20Sopenharmony_ci	desc.outbuf = buf;
4128c2ecf20Sopenharmony_ci	desc.pages = pages;
4138c2ecf20Sopenharmony_ci	desc.fragno = 0;
4148c2ecf20Sopenharmony_ci	desc.fraglen = 0;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	sg_init_table(desc.infrags, 4);
4178c2ecf20Sopenharmony_ci	sg_init_table(desc.outfrags, 4);
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	ret = xdr_process_buf(buf, offset, buf->len - offset, encryptor, &desc);
4208c2ecf20Sopenharmony_ci	skcipher_request_zero(req);
4218c2ecf20Sopenharmony_ci	return ret;
4228c2ecf20Sopenharmony_ci}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_cistruct decryptor_desc {
4258c2ecf20Sopenharmony_ci	u8 iv[GSS_KRB5_MAX_BLOCKSIZE];
4268c2ecf20Sopenharmony_ci	struct skcipher_request *req;
4278c2ecf20Sopenharmony_ci	struct scatterlist frags[4];
4288c2ecf20Sopenharmony_ci	int fragno;
4298c2ecf20Sopenharmony_ci	int fraglen;
4308c2ecf20Sopenharmony_ci};
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_cistatic int
4338c2ecf20Sopenharmony_cidecryptor(struct scatterlist *sg, void *data)
4348c2ecf20Sopenharmony_ci{
4358c2ecf20Sopenharmony_ci	struct decryptor_desc *desc = data;
4368c2ecf20Sopenharmony_ci	int thislen = desc->fraglen + sg->length;
4378c2ecf20Sopenharmony_ci	struct crypto_sync_skcipher *tfm =
4388c2ecf20Sopenharmony_ci		crypto_sync_skcipher_reqtfm(desc->req);
4398c2ecf20Sopenharmony_ci	int fraglen, ret;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	/* Worst case is 4 fragments: head, end of page 1, start
4428c2ecf20Sopenharmony_ci	 * of page 2, tail.  Anything more is a bug. */
4438c2ecf20Sopenharmony_ci	BUG_ON(desc->fragno > 3);
4448c2ecf20Sopenharmony_ci	sg_set_page(&desc->frags[desc->fragno], sg_page(sg), sg->length,
4458c2ecf20Sopenharmony_ci		    sg->offset);
4468c2ecf20Sopenharmony_ci	desc->fragno++;
4478c2ecf20Sopenharmony_ci	desc->fraglen += sg->length;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	fraglen = thislen & (crypto_sync_skcipher_blocksize(tfm) - 1);
4508c2ecf20Sopenharmony_ci	thislen -= fraglen;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	if (thislen == 0)
4538c2ecf20Sopenharmony_ci		return 0;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	sg_mark_end(&desc->frags[desc->fragno - 1]);
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	skcipher_request_set_crypt(desc->req, desc->frags, desc->frags,
4588c2ecf20Sopenharmony_ci				   thislen, desc->iv);
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	ret = crypto_skcipher_decrypt(desc->req);
4618c2ecf20Sopenharmony_ci	if (ret)
4628c2ecf20Sopenharmony_ci		return ret;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	sg_init_table(desc->frags, 4);
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	if (fraglen) {
4678c2ecf20Sopenharmony_ci		sg_set_page(&desc->frags[0], sg_page(sg), fraglen,
4688c2ecf20Sopenharmony_ci				sg->offset + sg->length - fraglen);
4698c2ecf20Sopenharmony_ci		desc->fragno = 1;
4708c2ecf20Sopenharmony_ci		desc->fraglen = fraglen;
4718c2ecf20Sopenharmony_ci	} else {
4728c2ecf20Sopenharmony_ci		desc->fragno = 0;
4738c2ecf20Sopenharmony_ci		desc->fraglen = 0;
4748c2ecf20Sopenharmony_ci	}
4758c2ecf20Sopenharmony_ci	return 0;
4768c2ecf20Sopenharmony_ci}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ciint
4798c2ecf20Sopenharmony_cigss_decrypt_xdr_buf(struct crypto_sync_skcipher *tfm, struct xdr_buf *buf,
4808c2ecf20Sopenharmony_ci		    int offset)
4818c2ecf20Sopenharmony_ci{
4828c2ecf20Sopenharmony_ci	int ret;
4838c2ecf20Sopenharmony_ci	struct decryptor_desc desc;
4848c2ecf20Sopenharmony_ci	SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	/* XXXJBF: */
4878c2ecf20Sopenharmony_ci	BUG_ON((buf->len - offset) % crypto_sync_skcipher_blocksize(tfm) != 0);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	skcipher_request_set_sync_tfm(req, tfm);
4908c2ecf20Sopenharmony_ci	skcipher_request_set_callback(req, 0, NULL, NULL);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	memset(desc.iv, 0, sizeof(desc.iv));
4938c2ecf20Sopenharmony_ci	desc.req = req;
4948c2ecf20Sopenharmony_ci	desc.fragno = 0;
4958c2ecf20Sopenharmony_ci	desc.fraglen = 0;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	sg_init_table(desc.frags, 4);
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	ret = xdr_process_buf(buf, offset, buf->len - offset, decryptor, &desc);
5008c2ecf20Sopenharmony_ci	skcipher_request_zero(req);
5018c2ecf20Sopenharmony_ci	return ret;
5028c2ecf20Sopenharmony_ci}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci/*
5058c2ecf20Sopenharmony_ci * This function makes the assumption that it was ultimately called
5068c2ecf20Sopenharmony_ci * from gss_wrap().
5078c2ecf20Sopenharmony_ci *
5088c2ecf20Sopenharmony_ci * The client auth_gss code moves any existing tail data into a
5098c2ecf20Sopenharmony_ci * separate page before calling gss_wrap.
5108c2ecf20Sopenharmony_ci * The server svcauth_gss code ensures that both the head and the
5118c2ecf20Sopenharmony_ci * tail have slack space of RPC_MAX_AUTH_SIZE before calling gss_wrap.
5128c2ecf20Sopenharmony_ci *
5138c2ecf20Sopenharmony_ci * Even with that guarantee, this function may be called more than
5148c2ecf20Sopenharmony_ci * once in the processing of gss_wrap().  The best we can do is
5158c2ecf20Sopenharmony_ci * verify at compile-time (see GSS_KRB5_SLACK_CHECK) that the
5168c2ecf20Sopenharmony_ci * largest expected shift will fit within RPC_MAX_AUTH_SIZE.
5178c2ecf20Sopenharmony_ci * At run-time we can verify that a single invocation of this
5188c2ecf20Sopenharmony_ci * function doesn't attempt to use more the RPC_MAX_AUTH_SIZE.
5198c2ecf20Sopenharmony_ci */
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ciint
5228c2ecf20Sopenharmony_cixdr_extend_head(struct xdr_buf *buf, unsigned int base, unsigned int shiftlen)
5238c2ecf20Sopenharmony_ci{
5248c2ecf20Sopenharmony_ci	u8 *p;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	if (shiftlen == 0)
5278c2ecf20Sopenharmony_ci		return 0;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	BUILD_BUG_ON(GSS_KRB5_MAX_SLACK_NEEDED > RPC_MAX_AUTH_SIZE);
5308c2ecf20Sopenharmony_ci	BUG_ON(shiftlen > RPC_MAX_AUTH_SIZE);
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	p = buf->head[0].iov_base + base;
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	memmove(p + shiftlen, p, buf->head[0].iov_len - base);
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	buf->head[0].iov_len += shiftlen;
5378c2ecf20Sopenharmony_ci	buf->len += shiftlen;
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	return 0;
5408c2ecf20Sopenharmony_ci}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_cistatic u32
5438c2ecf20Sopenharmony_cigss_krb5_cts_crypt(struct crypto_sync_skcipher *cipher, struct xdr_buf *buf,
5448c2ecf20Sopenharmony_ci		   u32 offset, u8 *iv, struct page **pages, int encrypt)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	u32 ret;
5478c2ecf20Sopenharmony_ci	struct scatterlist sg[1];
5488c2ecf20Sopenharmony_ci	SYNC_SKCIPHER_REQUEST_ON_STACK(req, cipher);
5498c2ecf20Sopenharmony_ci	u8 *data;
5508c2ecf20Sopenharmony_ci	struct page **save_pages;
5518c2ecf20Sopenharmony_ci	u32 len = buf->len - offset;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	if (len > GSS_KRB5_MAX_BLOCKSIZE * 2) {
5548c2ecf20Sopenharmony_ci		WARN_ON(0);
5558c2ecf20Sopenharmony_ci		return -ENOMEM;
5568c2ecf20Sopenharmony_ci	}
5578c2ecf20Sopenharmony_ci	data = kmalloc(GSS_KRB5_MAX_BLOCKSIZE * 2, GFP_NOFS);
5588c2ecf20Sopenharmony_ci	if (!data)
5598c2ecf20Sopenharmony_ci		return -ENOMEM;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	/*
5628c2ecf20Sopenharmony_ci	 * For encryption, we want to read from the cleartext
5638c2ecf20Sopenharmony_ci	 * page cache pages, and write the encrypted data to
5648c2ecf20Sopenharmony_ci	 * the supplied xdr_buf pages.
5658c2ecf20Sopenharmony_ci	 */
5668c2ecf20Sopenharmony_ci	save_pages = buf->pages;
5678c2ecf20Sopenharmony_ci	if (encrypt)
5688c2ecf20Sopenharmony_ci		buf->pages = pages;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	ret = read_bytes_from_xdr_buf(buf, offset, data, len);
5718c2ecf20Sopenharmony_ci	buf->pages = save_pages;
5728c2ecf20Sopenharmony_ci	if (ret)
5738c2ecf20Sopenharmony_ci		goto out;
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	sg_init_one(sg, data, len);
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	skcipher_request_set_sync_tfm(req, cipher);
5788c2ecf20Sopenharmony_ci	skcipher_request_set_callback(req, 0, NULL, NULL);
5798c2ecf20Sopenharmony_ci	skcipher_request_set_crypt(req, sg, sg, len, iv);
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	if (encrypt)
5828c2ecf20Sopenharmony_ci		ret = crypto_skcipher_encrypt(req);
5838c2ecf20Sopenharmony_ci	else
5848c2ecf20Sopenharmony_ci		ret = crypto_skcipher_decrypt(req);
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	skcipher_request_zero(req);
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	if (ret)
5898c2ecf20Sopenharmony_ci		goto out;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	ret = write_bytes_to_xdr_buf(buf, offset, data, len);
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ciout:
5948c2ecf20Sopenharmony_ci	kfree(data);
5958c2ecf20Sopenharmony_ci	return ret;
5968c2ecf20Sopenharmony_ci}
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ciu32
5998c2ecf20Sopenharmony_cigss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset,
6008c2ecf20Sopenharmony_ci		     struct xdr_buf *buf, struct page **pages)
6018c2ecf20Sopenharmony_ci{
6028c2ecf20Sopenharmony_ci	u32 err;
6038c2ecf20Sopenharmony_ci	struct xdr_netobj hmac;
6048c2ecf20Sopenharmony_ci	u8 *cksumkey;
6058c2ecf20Sopenharmony_ci	u8 *ecptr;
6068c2ecf20Sopenharmony_ci	struct crypto_sync_skcipher *cipher, *aux_cipher;
6078c2ecf20Sopenharmony_ci	int blocksize;
6088c2ecf20Sopenharmony_ci	struct page **save_pages;
6098c2ecf20Sopenharmony_ci	int nblocks, nbytes;
6108c2ecf20Sopenharmony_ci	struct encryptor_desc desc;
6118c2ecf20Sopenharmony_ci	u32 cbcbytes;
6128c2ecf20Sopenharmony_ci	unsigned int usage;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	if (kctx->initiate) {
6158c2ecf20Sopenharmony_ci		cipher = kctx->initiator_enc;
6168c2ecf20Sopenharmony_ci		aux_cipher = kctx->initiator_enc_aux;
6178c2ecf20Sopenharmony_ci		cksumkey = kctx->initiator_integ;
6188c2ecf20Sopenharmony_ci		usage = KG_USAGE_INITIATOR_SEAL;
6198c2ecf20Sopenharmony_ci	} else {
6208c2ecf20Sopenharmony_ci		cipher = kctx->acceptor_enc;
6218c2ecf20Sopenharmony_ci		aux_cipher = kctx->acceptor_enc_aux;
6228c2ecf20Sopenharmony_ci		cksumkey = kctx->acceptor_integ;
6238c2ecf20Sopenharmony_ci		usage = KG_USAGE_ACCEPTOR_SEAL;
6248c2ecf20Sopenharmony_ci	}
6258c2ecf20Sopenharmony_ci	blocksize = crypto_sync_skcipher_blocksize(cipher);
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	/* hide the gss token header and insert the confounder */
6288c2ecf20Sopenharmony_ci	offset += GSS_KRB5_TOK_HDR_LEN;
6298c2ecf20Sopenharmony_ci	if (xdr_extend_head(buf, offset, kctx->gk5e->conflen))
6308c2ecf20Sopenharmony_ci		return GSS_S_FAILURE;
6318c2ecf20Sopenharmony_ci	gss_krb5_make_confounder(buf->head[0].iov_base + offset, kctx->gk5e->conflen);
6328c2ecf20Sopenharmony_ci	offset -= GSS_KRB5_TOK_HDR_LEN;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	if (buf->tail[0].iov_base != NULL) {
6358c2ecf20Sopenharmony_ci		ecptr = buf->tail[0].iov_base + buf->tail[0].iov_len;
6368c2ecf20Sopenharmony_ci	} else {
6378c2ecf20Sopenharmony_ci		buf->tail[0].iov_base = buf->head[0].iov_base
6388c2ecf20Sopenharmony_ci							+ buf->head[0].iov_len;
6398c2ecf20Sopenharmony_ci		buf->tail[0].iov_len = 0;
6408c2ecf20Sopenharmony_ci		ecptr = buf->tail[0].iov_base;
6418c2ecf20Sopenharmony_ci	}
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	/* copy plaintext gss token header after filler (if any) */
6448c2ecf20Sopenharmony_ci	memcpy(ecptr, buf->head[0].iov_base + offset, GSS_KRB5_TOK_HDR_LEN);
6458c2ecf20Sopenharmony_ci	buf->tail[0].iov_len += GSS_KRB5_TOK_HDR_LEN;
6468c2ecf20Sopenharmony_ci	buf->len += GSS_KRB5_TOK_HDR_LEN;
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	/* Do the HMAC */
6498c2ecf20Sopenharmony_ci	hmac.len = GSS_KRB5_MAX_CKSUM_LEN;
6508c2ecf20Sopenharmony_ci	hmac.data = buf->tail[0].iov_base + buf->tail[0].iov_len;
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	/*
6538c2ecf20Sopenharmony_ci	 * When we are called, pages points to the real page cache
6548c2ecf20Sopenharmony_ci	 * data -- which we can't go and encrypt!  buf->pages points
6558c2ecf20Sopenharmony_ci	 * to scratch pages which we are going to send off to the
6568c2ecf20Sopenharmony_ci	 * client/server.  Swap in the plaintext pages to calculate
6578c2ecf20Sopenharmony_ci	 * the hmac.
6588c2ecf20Sopenharmony_ci	 */
6598c2ecf20Sopenharmony_ci	save_pages = buf->pages;
6608c2ecf20Sopenharmony_ci	buf->pages = pages;
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	err = make_checksum_v2(kctx, NULL, 0, buf,
6638c2ecf20Sopenharmony_ci			       offset + GSS_KRB5_TOK_HDR_LEN,
6648c2ecf20Sopenharmony_ci			       cksumkey, usage, &hmac);
6658c2ecf20Sopenharmony_ci	buf->pages = save_pages;
6668c2ecf20Sopenharmony_ci	if (err)
6678c2ecf20Sopenharmony_ci		return GSS_S_FAILURE;
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	nbytes = buf->len - offset - GSS_KRB5_TOK_HDR_LEN;
6708c2ecf20Sopenharmony_ci	nblocks = (nbytes + blocksize - 1) / blocksize;
6718c2ecf20Sopenharmony_ci	cbcbytes = 0;
6728c2ecf20Sopenharmony_ci	if (nblocks > 2)
6738c2ecf20Sopenharmony_ci		cbcbytes = (nblocks - 2) * blocksize;
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	memset(desc.iv, 0, sizeof(desc.iv));
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	if (cbcbytes) {
6788c2ecf20Sopenharmony_ci		SYNC_SKCIPHER_REQUEST_ON_STACK(req, aux_cipher);
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci		desc.pos = offset + GSS_KRB5_TOK_HDR_LEN;
6818c2ecf20Sopenharmony_ci		desc.fragno = 0;
6828c2ecf20Sopenharmony_ci		desc.fraglen = 0;
6838c2ecf20Sopenharmony_ci		desc.pages = pages;
6848c2ecf20Sopenharmony_ci		desc.outbuf = buf;
6858c2ecf20Sopenharmony_ci		desc.req = req;
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci		skcipher_request_set_sync_tfm(req, aux_cipher);
6888c2ecf20Sopenharmony_ci		skcipher_request_set_callback(req, 0, NULL, NULL);
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci		sg_init_table(desc.infrags, 4);
6918c2ecf20Sopenharmony_ci		sg_init_table(desc.outfrags, 4);
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci		err = xdr_process_buf(buf, offset + GSS_KRB5_TOK_HDR_LEN,
6948c2ecf20Sopenharmony_ci				      cbcbytes, encryptor, &desc);
6958c2ecf20Sopenharmony_ci		skcipher_request_zero(req);
6968c2ecf20Sopenharmony_ci		if (err)
6978c2ecf20Sopenharmony_ci			goto out_err;
6988c2ecf20Sopenharmony_ci	}
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	/* Make sure IV carries forward from any CBC results. */
7018c2ecf20Sopenharmony_ci	err = gss_krb5_cts_crypt(cipher, buf,
7028c2ecf20Sopenharmony_ci				 offset + GSS_KRB5_TOK_HDR_LEN + cbcbytes,
7038c2ecf20Sopenharmony_ci				 desc.iv, pages, 1);
7048c2ecf20Sopenharmony_ci	if (err) {
7058c2ecf20Sopenharmony_ci		err = GSS_S_FAILURE;
7068c2ecf20Sopenharmony_ci		goto out_err;
7078c2ecf20Sopenharmony_ci	}
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	/* Now update buf to account for HMAC */
7108c2ecf20Sopenharmony_ci	buf->tail[0].iov_len += kctx->gk5e->cksumlength;
7118c2ecf20Sopenharmony_ci	buf->len += kctx->gk5e->cksumlength;
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ciout_err:
7148c2ecf20Sopenharmony_ci	if (err)
7158c2ecf20Sopenharmony_ci		err = GSS_S_FAILURE;
7168c2ecf20Sopenharmony_ci	return err;
7178c2ecf20Sopenharmony_ci}
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ciu32
7208c2ecf20Sopenharmony_cigss_krb5_aes_decrypt(struct krb5_ctx *kctx, u32 offset, u32 len,
7218c2ecf20Sopenharmony_ci		     struct xdr_buf *buf, u32 *headskip, u32 *tailskip)
7228c2ecf20Sopenharmony_ci{
7238c2ecf20Sopenharmony_ci	struct xdr_buf subbuf;
7248c2ecf20Sopenharmony_ci	u32 ret = 0;
7258c2ecf20Sopenharmony_ci	u8 *cksum_key;
7268c2ecf20Sopenharmony_ci	struct crypto_sync_skcipher *cipher, *aux_cipher;
7278c2ecf20Sopenharmony_ci	struct xdr_netobj our_hmac_obj;
7288c2ecf20Sopenharmony_ci	u8 our_hmac[GSS_KRB5_MAX_CKSUM_LEN];
7298c2ecf20Sopenharmony_ci	u8 pkt_hmac[GSS_KRB5_MAX_CKSUM_LEN];
7308c2ecf20Sopenharmony_ci	int nblocks, blocksize, cbcbytes;
7318c2ecf20Sopenharmony_ci	struct decryptor_desc desc;
7328c2ecf20Sopenharmony_ci	unsigned int usage;
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	if (kctx->initiate) {
7358c2ecf20Sopenharmony_ci		cipher = kctx->acceptor_enc;
7368c2ecf20Sopenharmony_ci		aux_cipher = kctx->acceptor_enc_aux;
7378c2ecf20Sopenharmony_ci		cksum_key = kctx->acceptor_integ;
7388c2ecf20Sopenharmony_ci		usage = KG_USAGE_ACCEPTOR_SEAL;
7398c2ecf20Sopenharmony_ci	} else {
7408c2ecf20Sopenharmony_ci		cipher = kctx->initiator_enc;
7418c2ecf20Sopenharmony_ci		aux_cipher = kctx->initiator_enc_aux;
7428c2ecf20Sopenharmony_ci		cksum_key = kctx->initiator_integ;
7438c2ecf20Sopenharmony_ci		usage = KG_USAGE_INITIATOR_SEAL;
7448c2ecf20Sopenharmony_ci	}
7458c2ecf20Sopenharmony_ci	blocksize = crypto_sync_skcipher_blocksize(cipher);
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	/* create a segment skipping the header and leaving out the checksum */
7498c2ecf20Sopenharmony_ci	xdr_buf_subsegment(buf, &subbuf, offset + GSS_KRB5_TOK_HDR_LEN,
7508c2ecf20Sopenharmony_ci				    (len - offset - GSS_KRB5_TOK_HDR_LEN -
7518c2ecf20Sopenharmony_ci				     kctx->gk5e->cksumlength));
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	nblocks = (subbuf.len + blocksize - 1) / blocksize;
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	cbcbytes = 0;
7568c2ecf20Sopenharmony_ci	if (nblocks > 2)
7578c2ecf20Sopenharmony_ci		cbcbytes = (nblocks - 2) * blocksize;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	memset(desc.iv, 0, sizeof(desc.iv));
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	if (cbcbytes) {
7628c2ecf20Sopenharmony_ci		SYNC_SKCIPHER_REQUEST_ON_STACK(req, aux_cipher);
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci		desc.fragno = 0;
7658c2ecf20Sopenharmony_ci		desc.fraglen = 0;
7668c2ecf20Sopenharmony_ci		desc.req = req;
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci		skcipher_request_set_sync_tfm(req, aux_cipher);
7698c2ecf20Sopenharmony_ci		skcipher_request_set_callback(req, 0, NULL, NULL);
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci		sg_init_table(desc.frags, 4);
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci		ret = xdr_process_buf(&subbuf, 0, cbcbytes, decryptor, &desc);
7748c2ecf20Sopenharmony_ci		skcipher_request_zero(req);
7758c2ecf20Sopenharmony_ci		if (ret)
7768c2ecf20Sopenharmony_ci			goto out_err;
7778c2ecf20Sopenharmony_ci	}
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	/* Make sure IV carries forward from any CBC results. */
7808c2ecf20Sopenharmony_ci	ret = gss_krb5_cts_crypt(cipher, &subbuf, cbcbytes, desc.iv, NULL, 0);
7818c2ecf20Sopenharmony_ci	if (ret)
7828c2ecf20Sopenharmony_ci		goto out_err;
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	/* Calculate our hmac over the plaintext data */
7868c2ecf20Sopenharmony_ci	our_hmac_obj.len = sizeof(our_hmac);
7878c2ecf20Sopenharmony_ci	our_hmac_obj.data = our_hmac;
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	ret = make_checksum_v2(kctx, NULL, 0, &subbuf, 0,
7908c2ecf20Sopenharmony_ci			       cksum_key, usage, &our_hmac_obj);
7918c2ecf20Sopenharmony_ci	if (ret)
7928c2ecf20Sopenharmony_ci		goto out_err;
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	/* Get the packet's hmac value */
7958c2ecf20Sopenharmony_ci	ret = read_bytes_from_xdr_buf(buf, len - kctx->gk5e->cksumlength,
7968c2ecf20Sopenharmony_ci				      pkt_hmac, kctx->gk5e->cksumlength);
7978c2ecf20Sopenharmony_ci	if (ret)
7988c2ecf20Sopenharmony_ci		goto out_err;
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	if (crypto_memneq(pkt_hmac, our_hmac, kctx->gk5e->cksumlength) != 0) {
8018c2ecf20Sopenharmony_ci		ret = GSS_S_BAD_SIG;
8028c2ecf20Sopenharmony_ci		goto out_err;
8038c2ecf20Sopenharmony_ci	}
8048c2ecf20Sopenharmony_ci	*headskip = kctx->gk5e->conflen;
8058c2ecf20Sopenharmony_ci	*tailskip = kctx->gk5e->cksumlength;
8068c2ecf20Sopenharmony_ciout_err:
8078c2ecf20Sopenharmony_ci	if (ret && ret != GSS_S_BAD_SIG)
8088c2ecf20Sopenharmony_ci		ret = GSS_S_FAILURE;
8098c2ecf20Sopenharmony_ci	return ret;
8108c2ecf20Sopenharmony_ci}
811