3 * The Regents of the University of Michigan
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
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
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>
37 #include "gss_krb5_internal.h"
39 #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
40 # define RPCDBG_FACILITY RPCDBG_AUTH
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.
50 * If that proves to a problem perhaps we could use a more clever
53 #define LOCAL_BUF_LEN 32u
55 static void rotate_buf_a_little(struct xdr_buf
*buf
, unsigned int shift
)
57 char head
[LOCAL_BUF_LEN
];
58 char tmp
[LOCAL_BUF_LEN
];
59 unsigned int this_len
, i
;
61 BUG_ON(shift
> LOCAL_BUF_LEN
);
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
);
69 write_bytes_to_xdr_buf(buf
, buf
->len
- shift
, head
, shift
);
72 static void _rotate_left(struct xdr_buf
*buf
, unsigned int shift
)
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
;
85 static void rotate_left(u32 base
, struct xdr_buf
*buf
, unsigned int shift
)
87 struct xdr_buf subbuf
;
89 xdr_buf_subsegment(buf
, &subbuf
, base
, buf
->len
- base
);
90 _rotate_left(&subbuf
, shift
);
94 gss_krb5_wrap_v2(struct krb5_ctx
*kctx
, int offset
,
95 struct xdr_buf
*buf
, struct page
**pages
)
104 dprintk("RPC: %s\n", __func__
);
106 /* make room for gss token header */
107 if (xdr_extend_head(buf
, offset
, GSS_KRB5_TOK_HDR_LEN
))
108 return GSS_S_FAILURE
;
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);
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
;
124 be16ptr
= (__be16
*)ptr
;
127 /* "inner" token header always uses 0 for RRC */
130 be64ptr
= (__be64
*)be16ptr
;
131 *be64ptr
= cpu_to_be64(atomic64_fetch_inc(&kctx
->seq_send64
));
133 err
= (*kctx
->gk5e
->encrypt
)(kctx
, offset
, buf
, pages
);
137 now
= ktime_get_real_seconds();
138 return (kctx
->endtime
< now
) ? GSS_S_CONTEXT_EXPIRED
: GSS_S_COMPLETE
;
142 gss_krb5_unwrap_v2(struct krb5_ctx
*kctx
, int offset
, int len
,
143 struct xdr_buf
*buf
, unsigned int *slack
,
151 u32 headskip
, tailskip
;
152 u8 decrypted_hdr
[GSS_KRB5_TOK_HDR_LEN
];
153 unsigned int movelen
;
156 dprintk("RPC: %s\n", __func__
);
158 ptr
= buf
->head
[0].iov_base
+ offset
;
160 if (be16_to_cpu(*((__be16
*)ptr
)) != KG2_TOK_WRAP
)
161 return GSS_S_DEFECTIVE_TOKEN
;
164 if ((!kctx
->initiate
&& (flags
& KG2_TOKEN_FLAG_SENTBYACCEPTOR
)) ||
165 (kctx
->initiate
&& !(flags
& KG2_TOKEN_FLAG_SENTBYACCEPTOR
)))
166 return GSS_S_BAD_SIG
;
168 if ((flags
& KG2_TOKEN_FLAG_SEALED
) == 0) {
169 dprintk("%s: token missing expected sealed flag\n", __func__
);
170 return GSS_S_DEFECTIVE_TOKEN
;
174 return GSS_S_DEFECTIVE_TOKEN
;
176 ec
= be16_to_cpup((__be16
*)(ptr
+ 4));
177 rrc
= be16_to_cpup((__be16
*)(ptr
+ 6));
180 * NOTE: the sequence number at ptr + 8 is skipped, rpcsec_gss
181 * doesn't want it checked; see page 6 of rfc 2203.
185 rotate_left(offset
+ 16, buf
, rrc
);
187 err
= (*kctx
->gk5e
->decrypt
)(kctx
, offset
, len
, buf
,
188 &headskip
, &tailskip
);
190 return GSS_S_FAILURE
;
193 * Retrieve the decrypted gss token header and verify
194 * it against the original
196 err
= read_bytes_from_xdr_buf(buf
,
197 len
- GSS_KRB5_TOK_HDR_LEN
- tailskip
,
198 decrypted_hdr
, GSS_KRB5_TOK_HDR_LEN
);
200 dprintk("%s: error %u getting decrypted_hdr\n", __func__
, err
);
201 return GSS_S_FAILURE
;
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
;
209 /* do sequencing checks */
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
;
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.
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
);
231 /* Trim off the trailing "extra count" and checksum blob */
232 xdr_buf_trim(buf
, ec
+ GSS_KRB5_TOK_HDR_LEN
+ tailskip
);
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
;