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
xdr_extend_head(struct xdr_buf * buf,unsigned int base,unsigned int shiftlen)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
gss_krb5_aead_encrypt(struct krb5_ctx * kctx,u32 offset,struct xdr_buf * buf,struct page ** pages)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
gss_krb5_aead_decrypt(struct krb5_ctx * kctx,u32 offset,u32 len,struct xdr_buf * buf,u32 * headskip,u32 * tailskip)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 */
gss_krb5_mic_build_sg(const struct xdr_buf * body,void * cksum,unsigned int cksum_len,void * hdr,struct scatterlist * sg_head,struct scatterlist ** sg_overflow)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_objs(**sg_overflow, overflow_nents,
286 GFP_NOFS);
287 if (!*sg_overflow)
288 return -ENOMEM;
289
290 sg_init_table(sg_head, XDR_BUF_TO_SG_NENTS);
291 sg_init_table(*sg_overflow, overflow_nents);
292 sg_chain(sg_head, XDR_BUF_TO_SG_NENTS, *sg_overflow);
293 }
294
295 sg_set_buf(&sg_head[0], cksum, cksum_len);
296 body_nsg = xdr_buf_to_sg(body, 0, body->len,
297 sg_next(&sg_head[0]), body_max);
298 if (body_nsg < 0)
299 goto out_err;
300
301 /*
302 * xdr_buf_to_sg marks the last body entry as end-of-list;
303 * clear it so the trailing header entry is reachable.
304 */
305 if (body_nsg > 0) {
306 entry = sg_last(sg_next(&sg_head[0]), body_nsg);
307 sg_unmark_end(entry);
308 entry = sg_next(entry);
309 } else {
310 entry = sg_next(&sg_head[0]);
311 }
312 sg_set_buf(entry, hdr, GSS_KRB5_TOK_HDR_LEN);
313 sg_mark_end(entry);
314 return 1 + body_nsg + 1;
315
316 out_err:
317 kfree(*sg_overflow);
318 *sg_overflow = NULL;
319 return body_nsg;
320 }
321