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 } 238