/crypto/heimdal/lib/gssapi/krb5/8003.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 245 lines · 171 code · 29 blank · 45 comment · 33 complexity · c7befe3aa77fb8a2f983841d17f77490 MD5 · raw file

  1. /*
  2. * Copyright (c) 1997 - 2003 Kungliga Tekniska Hรถgskolan
  3. * (Royal Institute of Technology, Stockholm, Sweden).
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. *
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. *
  17. * 3. Neither the name of the Institute nor the names of its contributors
  18. * may be used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  22. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24. * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  25. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. */
  33. #include "gsskrb5_locl.h"
  34. krb5_error_code
  35. _gsskrb5_encode_om_uint32(OM_uint32 n, u_char *p)
  36. {
  37. p[0] = (n >> 0) & 0xFF;
  38. p[1] = (n >> 8) & 0xFF;
  39. p[2] = (n >> 16) & 0xFF;
  40. p[3] = (n >> 24) & 0xFF;
  41. return 0;
  42. }
  43. krb5_error_code
  44. _gsskrb5_encode_be_om_uint32(OM_uint32 n, u_char *p)
  45. {
  46. p[0] = (n >> 24) & 0xFF;
  47. p[1] = (n >> 16) & 0xFF;
  48. p[2] = (n >> 8) & 0xFF;
  49. p[3] = (n >> 0) & 0xFF;
  50. return 0;
  51. }
  52. krb5_error_code
  53. _gsskrb5_decode_om_uint32(const void *ptr, OM_uint32 *n)
  54. {
  55. const u_char *p = ptr;
  56. *n = (p[0] << 0) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
  57. return 0;
  58. }
  59. krb5_error_code
  60. _gsskrb5_decode_be_om_uint32(const void *ptr, OM_uint32 *n)
  61. {
  62. const u_char *p = ptr;
  63. *n = (p[0] <<24) | (p[1] << 16) | (p[2] << 8) | (p[3] << 0);
  64. return 0;
  65. }
  66. static krb5_error_code
  67. hash_input_chan_bindings (const gss_channel_bindings_t b,
  68. u_char *p)
  69. {
  70. u_char num[4];
  71. EVP_MD_CTX *ctx;
  72. ctx = EVP_MD_CTX_create();
  73. EVP_DigestInit_ex(ctx, EVP_md5(), NULL);
  74. _gsskrb5_encode_om_uint32 (b->initiator_addrtype, num);
  75. EVP_DigestUpdate(ctx, num, sizeof(num));
  76. _gsskrb5_encode_om_uint32 (b->initiator_address.length, num);
  77. EVP_DigestUpdate(ctx, num, sizeof(num));
  78. if (b->initiator_address.length)
  79. EVP_DigestUpdate(ctx,
  80. b->initiator_address.value,
  81. b->initiator_address.length);
  82. _gsskrb5_encode_om_uint32 (b->acceptor_addrtype, num);
  83. EVP_DigestUpdate(ctx, num, sizeof(num));
  84. _gsskrb5_encode_om_uint32 (b->acceptor_address.length, num);
  85. EVP_DigestUpdate(ctx, num, sizeof(num));
  86. if (b->acceptor_address.length)
  87. EVP_DigestUpdate(ctx,
  88. b->acceptor_address.value,
  89. b->acceptor_address.length);
  90. _gsskrb5_encode_om_uint32 (b->application_data.length, num);
  91. EVP_DigestUpdate(ctx, num, sizeof(num));
  92. if (b->application_data.length)
  93. EVP_DigestUpdate(ctx,
  94. b->application_data.value,
  95. b->application_data.length);
  96. EVP_DigestFinal_ex(ctx, p, NULL);
  97. EVP_MD_CTX_destroy(ctx);
  98. return 0;
  99. }
  100. /*
  101. * create a checksum over the chanel bindings in
  102. * `input_chan_bindings', `flags' and `fwd_data' and return it in
  103. * `result'
  104. */
  105. OM_uint32
  106. _gsskrb5_create_8003_checksum (
  107. OM_uint32 *minor_status,
  108. const gss_channel_bindings_t input_chan_bindings,
  109. OM_uint32 flags,
  110. const krb5_data *fwd_data,
  111. Checksum *result)
  112. {
  113. u_char *p;
  114. /*
  115. * see rfc1964 (section 1.1.1 (Initial Token), and the checksum value
  116. * field's format) */
  117. result->cksumtype = CKSUMTYPE_GSSAPI;
  118. if (fwd_data->length > 0 && (flags & GSS_C_DELEG_FLAG))
  119. result->checksum.length = 24 + 4 + fwd_data->length;
  120. else
  121. result->checksum.length = 24;
  122. result->checksum.data = malloc (result->checksum.length);
  123. if (result->checksum.data == NULL) {
  124. *minor_status = ENOMEM;
  125. return GSS_S_FAILURE;
  126. }
  127. p = result->checksum.data;
  128. _gsskrb5_encode_om_uint32 (16, p);
  129. p += 4;
  130. if (input_chan_bindings == GSS_C_NO_CHANNEL_BINDINGS) {
  131. memset (p, 0, 16);
  132. } else {
  133. hash_input_chan_bindings (input_chan_bindings, p);
  134. }
  135. p += 16;
  136. _gsskrb5_encode_om_uint32 (flags, p);
  137. p += 4;
  138. if (fwd_data->length > 0 && (flags & GSS_C_DELEG_FLAG)) {
  139. *p++ = (1 >> 0) & 0xFF; /* DlgOpt */ /* == 1 */
  140. *p++ = (1 >> 8) & 0xFF; /* DlgOpt */ /* == 0 */
  141. *p++ = (fwd_data->length >> 0) & 0xFF; /* Dlgth */
  142. *p++ = (fwd_data->length >> 8) & 0xFF; /* Dlgth */
  143. memcpy(p, (unsigned char *) fwd_data->data, fwd_data->length);
  144. p += fwd_data->length;
  145. }
  146. return GSS_S_COMPLETE;
  147. }
  148. /*
  149. * verify the checksum in `cksum' over `input_chan_bindings'
  150. * returning `flags' and `fwd_data'
  151. */
  152. OM_uint32
  153. _gsskrb5_verify_8003_checksum(
  154. OM_uint32 *minor_status,
  155. const gss_channel_bindings_t input_chan_bindings,
  156. const Checksum *cksum,
  157. OM_uint32 *flags,
  158. krb5_data *fwd_data)
  159. {
  160. unsigned char hash[16];
  161. unsigned char *p;
  162. OM_uint32 length;
  163. int DlgOpt;
  164. static unsigned char zeros[16];
  165. /* XXX should handle checksums > 24 bytes */
  166. if(cksum->cksumtype != CKSUMTYPE_GSSAPI || cksum->checksum.length < 24) {
  167. *minor_status = 0;
  168. return GSS_S_BAD_BINDINGS;
  169. }
  170. p = cksum->checksum.data;
  171. _gsskrb5_decode_om_uint32(p, &length);
  172. if(length != sizeof(hash)) {
  173. *minor_status = 0;
  174. return GSS_S_BAD_BINDINGS;
  175. }
  176. p += 4;
  177. if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS
  178. && memcmp(p, zeros, sizeof(zeros)) != 0) {
  179. if(hash_input_chan_bindings(input_chan_bindings, hash) != 0) {
  180. *minor_status = 0;
  181. return GSS_S_BAD_BINDINGS;
  182. }
  183. if(ct_memcmp(hash, p, sizeof(hash)) != 0) {
  184. *minor_status = 0;
  185. return GSS_S_BAD_BINDINGS;
  186. }
  187. }
  188. p += sizeof(hash);
  189. _gsskrb5_decode_om_uint32(p, flags);
  190. p += 4;
  191. if (cksum->checksum.length > 24 && (*flags & GSS_C_DELEG_FLAG)) {
  192. if(cksum->checksum.length < 28) {
  193. *minor_status = 0;
  194. return GSS_S_BAD_BINDINGS;
  195. }
  196. DlgOpt = (p[0] << 0) | (p[1] << 8);
  197. p += 2;
  198. if (DlgOpt != 1) {
  199. *minor_status = 0;
  200. return GSS_S_BAD_BINDINGS;
  201. }
  202. fwd_data->length = (p[0] << 0) | (p[1] << 8);
  203. p += 2;
  204. if(cksum->checksum.length < 28 + fwd_data->length) {
  205. *minor_status = 0;
  206. return GSS_S_BAD_BINDINGS;
  207. }
  208. fwd_data->data = malloc(fwd_data->length);
  209. if (fwd_data->data == NULL) {
  210. *minor_status = ENOMEM;
  211. return GSS_S_FAILURE;
  212. }
  213. memcpy(fwd_data->data, p, fwd_data->length);
  214. }
  215. return GSS_S_COMPLETE;
  216. }