gss_krb5_wrap.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  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. #include <crypto/skcipher.h>
  31. #include <linux/types.h>
  32. #include <linux/jiffies.h>
  33. #include <linux/sunrpc/gss_krb5.h>
  34. #include <linux/pagemap.h>
  35. #include "gss_krb5_internal.h"
  36. #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
  37. # define RPCDBG_FACILITY RPCDBG_AUTH
  38. #endif
  39. /*
  40. * We can shift data by up to LOCAL_BUF_LEN bytes in a pass. If we need
  41. * to do more than that, we shift repeatedly. Kevin Coffman reports
  42. * seeing 28 bytes as the value used by Microsoft clients and servers
  43. * with AES, so this constant is chosen to allow handling 28 in one pass
  44. * without using too much stack space.
  45. *
  46. * If that proves to a problem perhaps we could use a more clever
  47. * algorithm.
  48. */
  49. #define LOCAL_BUF_LEN 32u
  50. static void rotate_buf_a_little(struct xdr_buf *buf, unsigned int shift)
  51. {
  52. char head[LOCAL_BUF_LEN];
  53. char tmp[LOCAL_BUF_LEN];
  54. unsigned int this_len, i;
  55. BUG_ON(shift > LOCAL_BUF_LEN);
  56. read_bytes_from_xdr_buf(buf, 0, head, shift);
  57. for (i = 0; i + shift < buf->len; i += LOCAL_BUF_LEN) {
  58. this_len = min(LOCAL_BUF_LEN, buf->len - (i + shift));
  59. read_bytes_from_xdr_buf(buf, i+shift, tmp, this_len);
  60. write_bytes_to_xdr_buf(buf, i, tmp, this_len);
  61. }
  62. write_bytes_to_xdr_buf(buf, buf->len - shift, head, shift);
  63. }
  64. static void _rotate_left(struct xdr_buf *buf, unsigned int shift)
  65. {
  66. int shifted = 0;
  67. int this_shift;
  68. shift %= buf->len;
  69. while (shifted < shift) {
  70. this_shift = min(shift - shifted, LOCAL_BUF_LEN);
  71. rotate_buf_a_little(buf, this_shift);
  72. shifted += this_shift;
  73. }
  74. }
  75. static void rotate_left(u32 base, struct xdr_buf *buf, unsigned int shift)
  76. {
  77. struct xdr_buf subbuf;
  78. xdr_buf_subsegment(buf, &subbuf, base, buf->len - base);
  79. _rotate_left(&subbuf, shift);
  80. }
  81. u32
  82. gss_krb5_wrap_v2(struct krb5_ctx *kctx, int offset,
  83. struct xdr_buf *buf, struct page **pages)
  84. {
  85. u8 *ptr;
  86. time64_t now;
  87. u8 flags = 0x00;
  88. __be16 *be16ptr;
  89. __be64 *be64ptr;
  90. u32 err;
  91. dprintk("RPC: %s\n", __func__);
  92. /* make room for gss token header */
  93. if (xdr_extend_head(buf, offset, GSS_KRB5_TOK_HDR_LEN))
  94. return GSS_S_FAILURE;
  95. /* construct gss token header */
  96. ptr = buf->head[0].iov_base + offset;
  97. *ptr++ = (unsigned char) ((KG2_TOK_WRAP>>8) & 0xff);
  98. *ptr++ = (unsigned char) (KG2_TOK_WRAP & 0xff);
  99. if ((kctx->flags & KRB5_CTX_FLAG_INITIATOR) == 0)
  100. flags |= KG2_TOKEN_FLAG_SENTBYACCEPTOR;
  101. if ((kctx->flags & KRB5_CTX_FLAG_ACCEPTOR_SUBKEY) != 0)
  102. flags |= KG2_TOKEN_FLAG_ACCEPTORSUBKEY;
  103. /* We always do confidentiality in wrap tokens */
  104. flags |= KG2_TOKEN_FLAG_SEALED;
  105. *ptr++ = flags;
  106. *ptr++ = 0xff;
  107. be16ptr = (__be16 *)ptr;
  108. *be16ptr++ = 0;
  109. /* "inner" token header always uses 0 for RRC */
  110. *be16ptr++ = 0;
  111. be64ptr = (__be64 *)be16ptr;
  112. *be64ptr = cpu_to_be64(atomic64_fetch_inc(&kctx->seq_send64));
  113. err = (*kctx->gk5e->encrypt)(kctx, offset, buf, pages);
  114. if (err)
  115. return err;
  116. now = ktime_get_real_seconds();
  117. return (kctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE;
  118. }
  119. u32
  120. gss_krb5_unwrap_v2(struct krb5_ctx *kctx, int offset, int len,
  121. struct xdr_buf *buf, unsigned int *slack,
  122. unsigned int *align)
  123. {
  124. time64_t now;
  125. u8 *ptr;
  126. u8 flags = 0x00;
  127. u16 ec, rrc;
  128. int err;
  129. u32 headskip, tailskip;
  130. u8 decrypted_hdr[GSS_KRB5_TOK_HDR_LEN];
  131. unsigned int movelen;
  132. dprintk("RPC: %s\n", __func__);
  133. ptr = buf->head[0].iov_base + offset;
  134. if (be16_to_cpu(*((__be16 *)ptr)) != KG2_TOK_WRAP)
  135. return GSS_S_DEFECTIVE_TOKEN;
  136. flags = ptr[2];
  137. if ((!kctx->initiate && (flags & KG2_TOKEN_FLAG_SENTBYACCEPTOR)) ||
  138. (kctx->initiate && !(flags & KG2_TOKEN_FLAG_SENTBYACCEPTOR)))
  139. return GSS_S_BAD_SIG;
  140. if ((flags & KG2_TOKEN_FLAG_SEALED) == 0) {
  141. dprintk("%s: token missing expected sealed flag\n", __func__);
  142. return GSS_S_DEFECTIVE_TOKEN;
  143. }
  144. if (ptr[3] != 0xff)
  145. return GSS_S_DEFECTIVE_TOKEN;
  146. ec = be16_to_cpup((__be16 *)(ptr + 4));
  147. rrc = be16_to_cpup((__be16 *)(ptr + 6));
  148. /*
  149. * NOTE: the sequence number at ptr + 8 is skipped, rpcsec_gss
  150. * doesn't want it checked; see page 6 of rfc 2203.
  151. */
  152. if (rrc != 0)
  153. rotate_left(offset + 16, buf, rrc);
  154. err = (*kctx->gk5e->decrypt)(kctx, offset, len, buf,
  155. &headskip, &tailskip);
  156. if (err)
  157. return GSS_S_FAILURE;
  158. /*
  159. * Retrieve the decrypted gss token header and verify
  160. * it against the original
  161. */
  162. err = read_bytes_from_xdr_buf(buf,
  163. len - GSS_KRB5_TOK_HDR_LEN - tailskip,
  164. decrypted_hdr, GSS_KRB5_TOK_HDR_LEN);
  165. if (err) {
  166. dprintk("%s: error %u getting decrypted_hdr\n", __func__, err);
  167. return GSS_S_FAILURE;
  168. }
  169. if (memcmp(ptr, decrypted_hdr, 6)
  170. || memcmp(ptr + 8, decrypted_hdr + 8, 8)) {
  171. dprintk("%s: token hdr, plaintext hdr mismatch!\n", __func__);
  172. return GSS_S_FAILURE;
  173. }
  174. /* do sequencing checks */
  175. /* it got through unscathed. Make sure the context is unexpired */
  176. now = ktime_get_real_seconds();
  177. if (now > kctx->endtime)
  178. return GSS_S_CONTEXT_EXPIRED;
  179. /*
  180. * Move the head data back to the right position in xdr_buf.
  181. * We ignore any "ec" data since it might be in the head or
  182. * the tail, and we really don't need to deal with it.
  183. * Note that buf->head[0].iov_len may indicate the available
  184. * head buffer space rather than that actually occupied.
  185. */
  186. movelen = min_t(unsigned int, buf->head[0].iov_len, len);
  187. movelen -= offset + GSS_KRB5_TOK_HDR_LEN + headskip;
  188. BUG_ON(offset + GSS_KRB5_TOK_HDR_LEN + headskip + movelen >
  189. buf->head[0].iov_len);
  190. memmove(ptr, ptr + GSS_KRB5_TOK_HDR_LEN + headskip, movelen);
  191. buf->head[0].iov_len -= GSS_KRB5_TOK_HDR_LEN + headskip;
  192. buf->len = len - (GSS_KRB5_TOK_HDR_LEN + headskip);
  193. /* Trim off the trailing "extra count" and checksum blob */
  194. xdr_buf_trim(buf, ec + GSS_KRB5_TOK_HDR_LEN + tailskip);
  195. *align = XDR_QUADLEN(GSS_KRB5_TOK_HDR_LEN + headskip);
  196. *slack = *align + XDR_QUADLEN(ec + GSS_KRB5_TOK_HDR_LEN + tailskip);
  197. return GSS_S_COMPLETE;
  198. }