Linux Audio

Check our new training course

Loading...
  1/*
  2 * COPYRIGHT (c) 2008
  3 * The Regents of the University of Michigan
  4 * ALL RIGHTS RESERVED
  5 *
  6 * Permission is granted to use, copy, create derivative works
  7 * and redistribute this software and such derivative works
  8 * for any purpose, so long as the name of The University of
  9 * Michigan is not used in any advertising or publicity
 10 * pertaining to the use of distribution of this software
 11 * without specific, written prior authorization.  If the
 12 * above copyright notice or any other identification of the
 13 * University of Michigan is included in any copy of any
 14 * portion of this software, then the disclaimer below must
 15 * also be included.
 16 *
 17 * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
 18 * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
 19 * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
 20 * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
 21 * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
 22 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
 23 * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
 24 * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
 25 * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
 26 * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
 27 * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
 28 * SUCH DAMAGES.
 29 */
 30
 31#include <crypto/skcipher.h>
 32#include <linux/types.h>
 33#include <linux/jiffies.h>
 34#include <linux/sunrpc/gss_krb5.h>
 35#include <linux/pagemap.h>
 36
 37#include "gss_krb5_internal.h"
 38
 39#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
 40# define RPCDBG_FACILITY	RPCDBG_AUTH
 41#endif
 42
 43/*
 44 * We can shift data by up to LOCAL_BUF_LEN bytes in a pass.  If we need
 45 * to do more than that, we shift repeatedly.  Kevin Coffman reports
 46 * seeing 28 bytes as the value used by Microsoft clients and servers
 47 * with AES, so this constant is chosen to allow handling 28 in one pass
 48 * without using too much stack space.
 49 *
 50 * If that proves to a problem perhaps we could use a more clever
 51 * algorithm.
 52 */
 53#define LOCAL_BUF_LEN 32u
 54
 55static void rotate_buf_a_little(struct xdr_buf *buf, unsigned int shift)
 56{
 57	char head[LOCAL_BUF_LEN];
 58	char tmp[LOCAL_BUF_LEN];
 59	unsigned int this_len, i;
 60
 61	BUG_ON(shift > LOCAL_BUF_LEN);
 62
 63	read_bytes_from_xdr_buf(buf, 0, head, shift);
 64	for (i = 0; i + shift < buf->len; i += LOCAL_BUF_LEN) {
 65		this_len = min(LOCAL_BUF_LEN, buf->len - (i + shift));
 66		read_bytes_from_xdr_buf(buf, i+shift, tmp, this_len);
 67		write_bytes_to_xdr_buf(buf, i, tmp, this_len);
 68	}
 69	write_bytes_to_xdr_buf(buf, buf->len - shift, head, shift);
 70}
 71
 72static void _rotate_left(struct xdr_buf *buf, unsigned int shift)
 73{
 74	int shifted = 0;
 75	int this_shift;
 76
 77	shift %= buf->len;
 78	while (shifted < shift) {
 79		this_shift = min(shift - shifted, LOCAL_BUF_LEN);
 80		rotate_buf_a_little(buf, this_shift);
 81		shifted += this_shift;
 82	}
 83}
 84
 85static void rotate_left(u32 base, struct xdr_buf *buf, unsigned int shift)
 86{
 87	struct xdr_buf subbuf;
 88
 89	xdr_buf_subsegment(buf, &subbuf, base, buf->len - base);
 90	_rotate_left(&subbuf, shift);
 91}
 92
 93u32
 94gss_krb5_wrap_v2(struct krb5_ctx *kctx, int offset,
 95		 struct xdr_buf *buf, struct page **pages)
 96{
 97	u8		*ptr;
 98	time64_t	now;
 99	u8		flags = 0x00;
100	__be16		*be16ptr;
101	__be64		*be64ptr;
102	u32		err;
103
104	dprintk("RPC:       %s\n", __func__);
105
106	/* make room for gss token header */
107	if (xdr_extend_head(buf, offset, GSS_KRB5_TOK_HDR_LEN))
108		return GSS_S_FAILURE;
109
110	/* construct gss token header */
111	ptr = buf->head[0].iov_base + offset;
112	*ptr++ = (unsigned char) ((KG2_TOK_WRAP>>8) & 0xff);
113	*ptr++ = (unsigned char) (KG2_TOK_WRAP & 0xff);
114
115	if ((kctx->flags & KRB5_CTX_FLAG_INITIATOR) == 0)
116		flags |= KG2_TOKEN_FLAG_SENTBYACCEPTOR;
117	if ((kctx->flags & KRB5_CTX_FLAG_ACCEPTOR_SUBKEY) != 0)
118		flags |= KG2_TOKEN_FLAG_ACCEPTORSUBKEY;
119	/* We always do confidentiality in wrap tokens */
120	flags |= KG2_TOKEN_FLAG_SEALED;
121
122	*ptr++ = flags;
123	*ptr++ = 0xff;
124	be16ptr = (__be16 *)ptr;
125
126	*be16ptr++ = 0;
127	/* "inner" token header always uses 0 for RRC */
128	*be16ptr++ = 0;
129
130	be64ptr = (__be64 *)be16ptr;
131	*be64ptr = cpu_to_be64(atomic64_fetch_inc(&kctx->seq_send64));
132
133	err = (*kctx->gk5e->encrypt)(kctx, offset, buf, pages);
134	if (err)
135		return err;
136
137	now = ktime_get_real_seconds();
138	return (kctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
139}
140
141u32
142gss_krb5_unwrap_v2(struct krb5_ctx *kctx, int offset, int len,
143		   struct xdr_buf *buf, unsigned int *slack,
144		   unsigned int *align)
145{
146	time64_t	now;
147	u8		*ptr;
148	u8		flags = 0x00;
149	u16		ec, rrc;
150	int		err;
151	u32		headskip, tailskip;
152	u8		decrypted_hdr[GSS_KRB5_TOK_HDR_LEN];
153	unsigned int	movelen;
154
155
156	dprintk("RPC:       %s\n", __func__);
157
158	ptr = buf->head[0].iov_base + offset;
159
160	if (be16_to_cpu(*((__be16 *)ptr)) != KG2_TOK_WRAP)
161		return GSS_S_DEFECTIVE_TOKEN;
162
163	flags = ptr[2];
164	if ((!kctx->initiate && (flags & KG2_TOKEN_FLAG_SENTBYACCEPTOR)) ||
165	    (kctx->initiate && !(flags & KG2_TOKEN_FLAG_SENTBYACCEPTOR)))
166		return GSS_S_BAD_SIG;
167
168	if ((flags & KG2_TOKEN_FLAG_SEALED) == 0) {
169		dprintk("%s: token missing expected sealed flag\n", __func__);
170		return GSS_S_DEFECTIVE_TOKEN;
171	}
172
173	if (ptr[3] != 0xff)
174		return GSS_S_DEFECTIVE_TOKEN;
175
176	ec = be16_to_cpup((__be16 *)(ptr + 4));
177	rrc = be16_to_cpup((__be16 *)(ptr + 6));
178
179	/*
180	 * NOTE: the sequence number at ptr + 8 is skipped, rpcsec_gss
181	 * doesn't want it checked; see page 6 of rfc 2203.
182	 */
183
184	if (rrc != 0)
185		rotate_left(offset + 16, buf, rrc);
186
187	err = (*kctx->gk5e->decrypt)(kctx, offset, len, buf,
188				     &headskip, &tailskip);
189	if (err)
190		return GSS_S_FAILURE;
191
192	/*
193	 * Retrieve the decrypted gss token header and verify
194	 * it against the original
195	 */
196	err = read_bytes_from_xdr_buf(buf,
197				len - GSS_KRB5_TOK_HDR_LEN - tailskip,
198				decrypted_hdr, GSS_KRB5_TOK_HDR_LEN);
199	if (err) {
200		dprintk("%s: error %u getting decrypted_hdr\n", __func__, err);
201		return GSS_S_FAILURE;
202	}
203	if (memcmp(ptr, decrypted_hdr, 6)
204				|| memcmp(ptr + 8, decrypted_hdr + 8, 8)) {
205		dprintk("%s: token hdr, plaintext hdr mismatch!\n", __func__);
206		return GSS_S_FAILURE;
207	}
208
209	/* do sequencing checks */
210
211	/* it got through unscathed.  Make sure the context is unexpired */
212	now = ktime_get_real_seconds();
213	if (now > kctx->endtime)
214		return GSS_S_CONTEXT_EXPIRED;
215
216	/*
217	 * Move the head data back to the right position in xdr_buf.
218	 * We ignore any "ec" data since it might be in the head or
219	 * the tail, and we really don't need to deal with it.
220	 * Note that buf->head[0].iov_len may indicate the available
221	 * head buffer space rather than that actually occupied.
222	 */
223	movelen = min_t(unsigned int, buf->head[0].iov_len, len);
224	movelen -= offset + GSS_KRB5_TOK_HDR_LEN + headskip;
225	BUG_ON(offset + GSS_KRB5_TOK_HDR_LEN + headskip + movelen >
226							buf->head[0].iov_len);
227	memmove(ptr, ptr + GSS_KRB5_TOK_HDR_LEN + headskip, movelen);
228	buf->head[0].iov_len -= GSS_KRB5_TOK_HDR_LEN + headskip;
229	buf->len = len - (GSS_KRB5_TOK_HDR_LEN + headskip);
230
231	/* Trim off the trailing "extra count" and checksum blob */
232	xdr_buf_trim(buf, ec + GSS_KRB5_TOK_HDR_LEN + tailskip);
233
234	*align = XDR_QUADLEN(GSS_KRB5_TOK_HDR_LEN + headskip);
235	*slack = *align + XDR_QUADLEN(ec + GSS_KRB5_TOK_HDR_LEN + tailskip);
236	return GSS_S_COMPLETE;
237}