Mention branches and keyring.
[releases.git] / sunrpc / auth_gss / gss_krb5_wrap.c
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
55 static 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
72 static 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
85 static 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
93 u32
94 gss_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
141 u32
142 gss_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 }