1 /* 2 * linux/net/sunrpc/gss_krb5_crypto.c 3 * 4 * Copyright (c) 2000-2008 The Regents of the University of Michigan. 5 * All rights reserved. 6 * 7 * Andy Adamson <andros@umich.edu> 8 * Bruce Fields <bfields@umich.edu> 9 */ 10 11 /* 12 * Copyright (C) 1998 by the FundsXpress, INC. 13 * 14 * All rights reserved. 15 * 16 * Export of this software from the United States of America may require 17 * a specific license from the United States Government. It is the 18 * responsibility of any person or organization contemplating export to 19 * obtain such a license before exporting. 20 * 21 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 22 * distribute this software and its documentation for any purpose and 23 * without fee is hereby granted, provided that the above copyright 24 * notice appear in all copies and that both that copyright notice and 25 * this permission notice appear in supporting documentation, and that 26 * the name of FundsXpress. not be used in advertising or publicity pertaining 27 * to distribution of the software without specific, written prior 28 * permission. FundsXpress makes no representations about the suitability of 29 * this software for any purpose. It is provided "as is" without express 30 * or implied warranty. 31 * 32 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 33 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 34 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 35 */ 36 37 #include <linux/err.h> 38 #include <linux/types.h> 39 #include <linux/mm.h> 40 #include <linux/scatterlist.h> 41 #include <linux/highmem.h> 42 #include <linux/pagemap.h> 43 #include <linux/sunrpc/gss_krb5.h> 44 #include <linux/sunrpc/xdr.h> 45 46 #include "gss_krb5_internal.h" 47 48 #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) 49 # define RPCDBG_FACILITY RPCDBG_AUTH 50 #endif 51 52 53 /* 54 * This function makes the assumption that it was ultimately called 55 * from gss_wrap(). 56 * 57 * The client auth_gss code moves any existing tail data into a 58 * separate page before calling gss_wrap. 59 * The server svcauth_gss code ensures that both the head and the 60 * tail have slack space of RPC_MAX_AUTH_SIZE before calling gss_wrap. 61 * 62 * Even with that guarantee, this function may be called more than 63 * once in the processing of gss_wrap(). The best we can do is 64 * verify at compile-time (see GSS_KRB5_MAX_SLACK_NEEDED) that the 65 * largest expected shift will fit within RPC_MAX_AUTH_SIZE. 66 * At run-time we can verify that a single invocation of this 67 * function doesn't attempt to use more the RPC_MAX_AUTH_SIZE. 68 */ 69 70 int 71 xdr_extend_head(struct xdr_buf *buf, unsigned int base, unsigned int shiftlen) 72 { 73 u8 *p; 74 75 if (shiftlen == 0) 76 return 0; 77 78 BUG_ON(shiftlen > RPC_MAX_AUTH_SIZE); 79 80 p = buf->head[0].iov_base + base; 81 82 memmove(p + shiftlen, p, buf->head[0].iov_len - base); 83 84 buf->head[0].iov_len += shiftlen; 85 buf->len += shiftlen; 86 87 return 0; 88 } 89 90 91 /** 92 * gss_krb5_aead_encrypt - Encrypt a wrap token using crypto/krb5 93 * @kctx: Kerberos context 94 * @offset: byte offset of the GSS token header in @buf 95 * @buf: OUT: send buffer 96 * @pages: plaintext payload pages (page cache data) 97 * 98 * The xdr_buf setup mirrors the original per-enctype encrypt 99 * functions, but the CBC-CTS encryption and HMAC are replaced 100 * by a single AEAD operation through the crypto/krb5 library. 101 * 102 * Return values: 103 * %GSS_S_COMPLETE: Encryption successful 104 * %GSS_S_FAILURE: Encryption failed 105 */ 106 u32 107 gss_krb5_aead_encrypt(struct krb5_ctx *kctx, u32 offset, 108 struct xdr_buf *buf, struct page **pages) 109 { 110 const struct krb5_enctype *krb5 = kctx->krb5e; 111 struct crypto_aead *aead = kctx->initiate ? 112 kctx->initiator_enc_aead : kctx->acceptor_enc_aead; 113 unsigned int conflen = krb5->conf_len; 114 unsigned int cksum_len = krb5->cksum_len; 115 unsigned int sec_offset, sec_len, data_len; 116 struct scatterlist sg[XDR_BUF_TO_SG_NENTS]; 117 struct scatterlist *sg_overflow = NULL; 118 ssize_t ret; 119 int nsg; 120 121 /* Insert space for the confounder */ 122 if (xdr_extend_head(buf, offset + GSS_KRB5_TOK_HDR_LEN, conflen)) 123 return GSS_S_FAILURE; 124 125 /* Ensure a tail segment exists */ 126 if (buf->tail[0].iov_base == NULL) { 127 buf->tail[0].iov_base = buf->head[0].iov_base 128 + buf->head[0].iov_len; 129 buf->tail[0].iov_len = 0; 130 } 131 132 /* Append a copy of the plaintext GSS token header (RFC 4121 Sec 4.2.4) */ 133 memcpy(buf->tail[0].iov_base + buf->tail[0].iov_len, 134 buf->head[0].iov_base + offset, GSS_KRB5_TOK_HDR_LEN); 135 buf->tail[0].iov_len += GSS_KRB5_TOK_HDR_LEN; 136 buf->len += GSS_KRB5_TOK_HDR_LEN; 137 138 /* Reserve space for the integrity checksum */ 139 buf->tail[0].iov_len += cksum_len; 140 buf->len += cksum_len; 141 142 /* 143 * The AEAD operates in-place, but on the client send path the 144 * plaintext payload lives in page cache pages that must not be 145 * modified. Copy the payload into the scratch output pages 146 * first. On the server send path @pages and buf->pages are 147 * the same array, and no copy is needed. 148 * 149 * Both arrays share buf->page_base, so the same index and 150 * intra-page offset address corresponding data in each. 151 */ 152 if (pages != buf->pages) { 153 unsigned int poff = buf->page_base; 154 unsigned int plen = buf->page_len; 155 unsigned int i = poff >> PAGE_SHIFT; 156 unsigned int off = offset_in_page(poff); 157 158 while (plen) { 159 unsigned int n = min_t(unsigned int, plen, 160 PAGE_SIZE - off); 161 memcpy_page(buf->pages[i], off, pages[i], off, n); 162 plen -= n; 163 i++; 164 off = 0; 165 } 166 } 167 168 /* Build scatterlist covering the secured region */ 169 sec_offset = offset + GSS_KRB5_TOK_HDR_LEN; 170 sec_len = buf->len - sec_offset; 171 data_len = sec_len - conflen - cksum_len; 172 173 nsg = xdr_buf_to_sg_alloc(buf, sec_offset, sec_len, 174 sg, ARRAY_SIZE(sg), 175 &sg_overflow, GFP_NOFS); 176 if (nsg < 0) 177 return GSS_S_FAILURE; 178 179 ret = crypto_krb5_encrypt(krb5, aead, sg, nsg, sec_len, 180 conflen, data_len, false); 181 kfree(sg_overflow); 182 if (ret < 0) 183 return GSS_S_FAILURE; 184 185 return GSS_S_COMPLETE; 186 } 187 188 /** 189 * gss_krb5_aead_decrypt - Decrypt a wrap token using crypto/krb5 190 * @kctx: Kerberos context 191 * @offset: byte offset of the GSS token header in @buf 192 * @len: total length of the GSS token 193 * @buf: ciphertext buffer, decrypted in-place 194 * @headskip: OUT: confounder length, in octets 195 * @tailskip: OUT: checksum length, in octets 196 * 197 * Return values: 198 * %GSS_S_COMPLETE: Decryption and integrity verification succeeded 199 * %GSS_S_BAD_SIG: Integrity checksum did not match 200 * %GSS_S_DEFECTIVE_TOKEN: Token is malformed or truncated 201 * %GSS_S_FAILURE: Decryption failed 202 */ 203 u32 204 gss_krb5_aead_decrypt(struct krb5_ctx *kctx, u32 offset, u32 len, 205 struct xdr_buf *buf, u32 *headskip, u32 *tailskip) 206 { 207 const struct krb5_enctype *krb5 = kctx->krb5e; 208 struct crypto_aead *aead = kctx->initiate ? 209 kctx->acceptor_enc_aead : kctx->initiator_enc_aead; 210 unsigned int sec_offset, sec_len; 211 size_t data_offset, data_len; 212 struct scatterlist sg[XDR_BUF_TO_SG_NENTS]; 213 struct scatterlist *sg_overflow = NULL; 214 int nsg, ret; 215 216 /* Secured region starts after the GSS token header */ 217 sec_offset = offset + GSS_KRB5_TOK_HDR_LEN; 218 if (len < sec_offset) 219 return GSS_S_DEFECTIVE_TOKEN; 220 sec_len = len - sec_offset; 221 222 nsg = xdr_buf_to_sg_alloc(buf, sec_offset, sec_len, 223 sg, ARRAY_SIZE(sg), 224 &sg_overflow, GFP_NOFS); 225 if (nsg < 0) 226 return GSS_S_FAILURE; 227 228 data_offset = 0; 229 data_len = sec_len; 230 ret = crypto_krb5_decrypt(krb5, aead, sg, nsg, 231 &data_offset, &data_len); 232 kfree(sg_overflow); 233 if (ret < 0) 234 return gss_krb5_errno_to_status(ret); 235 236 *headskip = data_offset; 237 *tailskip = sec_len - data_offset - data_len; 238 return GSS_S_COMPLETE; 239 } 240 241 /** 242 * gss_krb5_mic_build_sg - Build scatterlist for MIC token operations 243 * @body: xdr_buf containing the message body 244 * @cksum: pointer to checksum area in the token buffer 245 * @cksum_len: length of checksum area 246 * @hdr: pointer to GSS token header 247 * @sg_head: caller-provided scatterlist array; if more than 248 * XDR_BUF_TO_SG_NENTS entries are needed, an overflow 249 * scatterlist is allocated and chained automatically 250 * @sg_overflow: OUT: overflow scatterlist, caller must kfree 251 * 252 * Per RFC 4121 Section 4.2.4, MIC token checksums cover the 253 * message body followed by the token header. The checksum 254 * output or received checksum occupies the first scatterlist 255 * entry. This layout cannot be constructed by 256 * xdr_buf_to_sg_alloc() because the checksum area and the GSS 257 * header lie outside the xdr_buf. 258 * 259 * Returns the number of scatterlist entries on success, or a 260 * negative errno on failure. 261 */ 262 int gss_krb5_mic_build_sg(const struct xdr_buf *body, 263 void *cksum, unsigned int cksum_len, 264 void *hdr, 265 struct scatterlist *sg_head, 266 struct scatterlist **sg_overflow) 267 { 268 struct scatterlist *entry; 269 int body_max, body_nsg, nsg; 270 271 *sg_overflow = NULL; 272 273 body_max = 2; 274 if (body->page_len) 275 body_max += DIV_ROUND_UP(body->page_len + 276 offset_in_page(body->page_base), 277 PAGE_SIZE); 278 nsg = 1 + body_max + 1; 279 if (nsg <= XDR_BUF_TO_SG_NENTS) { 280 sg_init_table(sg_head, nsg); 281 } else { 282 unsigned int overflow_nents = 283 nsg - XDR_BUF_TO_SG_NENTS + 1; 284 285 *sg_overflow = kmalloc_array(overflow_nents, 286 sizeof(**sg_overflow), 287 GFP_NOFS); 288 if (!*sg_overflow) 289 return -ENOMEM; 290 291 sg_init_table(sg_head, XDR_BUF_TO_SG_NENTS); 292 sg_init_table(*sg_overflow, overflow_nents); 293 sg_chain(sg_head, XDR_BUF_TO_SG_NENTS, *sg_overflow); 294 } 295 296 sg_set_buf(&sg_head[0], cksum, cksum_len); 297 body_nsg = xdr_buf_to_sg(body, 0, body->len, 298 sg_next(&sg_head[0]), body_max); 299 if (body_nsg < 0) 300 goto out_err; 301 302 /* 303 * xdr_buf_to_sg marks the last body entry as end-of-list; 304 * clear it so the trailing header entry is reachable. 305 */ 306 if (body_nsg > 0) { 307 entry = sg_last(sg_next(&sg_head[0]), body_nsg); 308 sg_unmark_end(entry); 309 entry = sg_next(entry); 310 } else { 311 entry = sg_next(&sg_head[0]); 312 } 313 sg_set_buf(entry, hdr, GSS_KRB5_TOK_HDR_LEN); 314 sg_mark_end(entry); 315 return 1 + body_nsg + 1; 316 317 out_err: 318 kfree(*sg_overflow); 319 *sg_overflow = NULL; 320 return body_nsg; 321 } 322