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