/crypto/heimdal/lib/gssapi/spnego/compat.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 317 lines · 207 code · 48 blank · 62 comment · 51 complexity · 2bfc628fb3919939d793f62eed07d6e4 MD5 · raw file

  1. /*
  2. * Copyright (c) 2004, PADL Software Pty Ltd.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. *
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. *
  16. * 3. Neither the name of PADL Software nor the names of its contributors
  17. * may be used to endorse or promote products derived from this software
  18. * without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
  21. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23. * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
  24. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30. * SUCH DAMAGE.
  31. */
  32. #include "spnego_locl.h"
  33. /*
  34. * Apparently Microsoft got the OID wrong, and used
  35. * 1.2.840.48018.1.2.2 instead. We need both this and
  36. * the correct Kerberos OID here in order to deal with
  37. * this. Because this is manifest in SPNEGO only I'd
  38. * prefer to deal with this here rather than inside the
  39. * Kerberos mechanism.
  40. */
  41. gss_OID_desc _gss_spnego_mskrb_mechanism_oid_desc =
  42. {9, rk_UNCONST("\x2a\x86\x48\x82\xf7\x12\x01\x02\x02")};
  43. gss_OID_desc _gss_spnego_krb5_mechanism_oid_desc =
  44. {9, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02")};
  45. /*
  46. * Allocate a SPNEGO context handle
  47. */
  48. OM_uint32 GSSAPI_CALLCONV
  49. _gss_spnego_alloc_sec_context (OM_uint32 * minor_status,
  50. gss_ctx_id_t *context_handle)
  51. {
  52. gssspnego_ctx ctx;
  53. ctx = calloc(1, sizeof(*ctx));
  54. if (ctx == NULL) {
  55. *minor_status = ENOMEM;
  56. return GSS_S_FAILURE;
  57. }
  58. ctx->initiator_mech_types.len = 0;
  59. ctx->initiator_mech_types.val = NULL;
  60. ctx->preferred_mech_type = GSS_C_NO_OID;
  61. ctx->negotiated_mech_type = GSS_C_NO_OID;
  62. ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT;
  63. /*
  64. * Cache these so we can return them before returning
  65. * GSS_S_COMPLETE, even if the mechanism has itself
  66. * completed earlier
  67. */
  68. ctx->mech_flags = 0;
  69. ctx->mech_time_rec = 0;
  70. ctx->mech_src_name = GSS_C_NO_NAME;
  71. ctx->open = 0;
  72. ctx->local = 0;
  73. ctx->require_mic = 0;
  74. ctx->verified_mic = 0;
  75. HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex);
  76. *context_handle = (gss_ctx_id_t)ctx;
  77. return GSS_S_COMPLETE;
  78. }
  79. /*
  80. * Free a SPNEGO context handle. The caller must have acquired
  81. * the lock before this is called.
  82. */
  83. OM_uint32 GSSAPI_CALLCONV _gss_spnego_internal_delete_sec_context
  84. (OM_uint32 *minor_status,
  85. gss_ctx_id_t *context_handle,
  86. gss_buffer_t output_token
  87. )
  88. {
  89. gssspnego_ctx ctx;
  90. OM_uint32 ret, minor;
  91. *minor_status = 0;
  92. if (context_handle == NULL) {
  93. return GSS_S_NO_CONTEXT;
  94. }
  95. if (output_token != GSS_C_NO_BUFFER) {
  96. output_token->length = 0;
  97. output_token->value = NULL;
  98. }
  99. ctx = (gssspnego_ctx)*context_handle;
  100. *context_handle = GSS_C_NO_CONTEXT;
  101. if (ctx == NULL) {
  102. return GSS_S_NO_CONTEXT;
  103. }
  104. if (ctx->initiator_mech_types.val != NULL)
  105. free_MechTypeList(&ctx->initiator_mech_types);
  106. gss_release_oid(&minor, &ctx->preferred_mech_type);
  107. ctx->negotiated_mech_type = GSS_C_NO_OID;
  108. gss_release_name(&minor, &ctx->target_name);
  109. gss_release_name(&minor, &ctx->mech_src_name);
  110. if (ctx->negotiated_ctx_id != GSS_C_NO_CONTEXT) {
  111. ret = gss_delete_sec_context(minor_status,
  112. &ctx->negotiated_ctx_id,
  113. output_token);
  114. ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT;
  115. } else {
  116. ret = GSS_S_COMPLETE;
  117. }
  118. HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
  119. HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);
  120. free(ctx);
  121. return ret;
  122. }
  123. /*
  124. * For compatability with the Windows SPNEGO implementation, the
  125. * default is to ignore the mechListMIC unless CFX is used and
  126. * a non-preferred mechanism was negotiated
  127. */
  128. OM_uint32 GSSAPI_CALLCONV
  129. _gss_spnego_require_mechlist_mic(OM_uint32 *minor_status,
  130. gssspnego_ctx ctx,
  131. int *require_mic)
  132. {
  133. gss_buffer_set_t buffer_set = GSS_C_NO_BUFFER_SET;
  134. OM_uint32 minor;
  135. *minor_status = 0;
  136. *require_mic = 0;
  137. if (ctx == NULL) {
  138. return GSS_S_COMPLETE;
  139. }
  140. if (ctx->require_mic) {
  141. /* Acceptor requested it: mandatory to honour */
  142. *require_mic = 1;
  143. return GSS_S_COMPLETE;
  144. }
  145. /*
  146. * Check whether peer indicated implicit support for updated SPNEGO
  147. * (eg. in the Kerberos case by using CFX)
  148. */
  149. if (gss_inquire_sec_context_by_oid(&minor, ctx->negotiated_ctx_id,
  150. GSS_C_PEER_HAS_UPDATED_SPNEGO,
  151. &buffer_set) == GSS_S_COMPLETE) {
  152. *require_mic = 1;
  153. gss_release_buffer_set(&minor, &buffer_set);
  154. }
  155. /* Safe-to-omit MIC rules follow */
  156. if (*require_mic) {
  157. if (gss_oid_equal(ctx->negotiated_mech_type, ctx->preferred_mech_type)) {
  158. *require_mic = 0;
  159. } else if (gss_oid_equal(ctx->negotiated_mech_type, &_gss_spnego_krb5_mechanism_oid_desc) &&
  160. gss_oid_equal(ctx->preferred_mech_type, &_gss_spnego_mskrb_mechanism_oid_desc)) {
  161. *require_mic = 0;
  162. }
  163. }
  164. return GSS_S_COMPLETE;
  165. }
  166. static int
  167. add_mech_type(gss_OID mech_type,
  168. int includeMSCompatOID,
  169. MechTypeList *mechtypelist)
  170. {
  171. MechType mech;
  172. int ret;
  173. if (gss_oid_equal(mech_type, GSS_SPNEGO_MECHANISM))
  174. return 0;
  175. if (includeMSCompatOID &&
  176. gss_oid_equal(mech_type, &_gss_spnego_krb5_mechanism_oid_desc)) {
  177. ret = der_get_oid(_gss_spnego_mskrb_mechanism_oid_desc.elements,
  178. _gss_spnego_mskrb_mechanism_oid_desc.length,
  179. &mech,
  180. NULL);
  181. if (ret)
  182. return ret;
  183. ret = add_MechTypeList(mechtypelist, &mech);
  184. free_MechType(&mech);
  185. if (ret)
  186. return ret;
  187. }
  188. ret = der_get_oid(mech_type->elements, mech_type->length, &mech, NULL);
  189. if (ret)
  190. return ret;
  191. ret = add_MechTypeList(mechtypelist, &mech);
  192. free_MechType(&mech);
  193. return ret;
  194. }
  195. OM_uint32 GSSAPI_CALLCONV
  196. _gss_spnego_indicate_mechtypelist (OM_uint32 *minor_status,
  197. gss_name_t target_name,
  198. OM_uint32 (*func)(gss_name_t, gss_OID),
  199. int includeMSCompatOID,
  200. const gss_cred_id_t cred_handle,
  201. MechTypeList *mechtypelist,
  202. gss_OID *preferred_mech)
  203. {
  204. gss_OID_set supported_mechs = GSS_C_NO_OID_SET;
  205. gss_OID first_mech = GSS_C_NO_OID;
  206. OM_uint32 ret;
  207. size_t i;
  208. mechtypelist->len = 0;
  209. mechtypelist->val = NULL;
  210. if (cred_handle) {
  211. ret = gss_inquire_cred(minor_status,
  212. cred_handle,
  213. NULL,
  214. NULL,
  215. NULL,
  216. &supported_mechs);
  217. } else {
  218. ret = gss_indicate_mechs(minor_status, &supported_mechs);
  219. }
  220. if (ret != GSS_S_COMPLETE) {
  221. return ret;
  222. }
  223. if (supported_mechs->count == 0) {
  224. *minor_status = ENOENT;
  225. gss_release_oid_set(minor_status, &supported_mechs);
  226. return GSS_S_FAILURE;
  227. }
  228. ret = (*func)(target_name, GSS_KRB5_MECHANISM);
  229. if (ret == GSS_S_COMPLETE) {
  230. ret = add_mech_type(GSS_KRB5_MECHANISM,
  231. includeMSCompatOID,
  232. mechtypelist);
  233. if (!GSS_ERROR(ret))
  234. first_mech = GSS_KRB5_MECHANISM;
  235. }
  236. ret = GSS_S_COMPLETE;
  237. for (i = 0; i < supported_mechs->count; i++) {
  238. OM_uint32 subret;
  239. if (gss_oid_equal(&supported_mechs->elements[i], GSS_SPNEGO_MECHANISM))
  240. continue;
  241. if (gss_oid_equal(&supported_mechs->elements[i], GSS_KRB5_MECHANISM))
  242. continue;
  243. subret = (*func)(target_name, &supported_mechs->elements[i]);
  244. if (subret != GSS_S_COMPLETE)
  245. continue;
  246. ret = add_mech_type(&supported_mechs->elements[i],
  247. includeMSCompatOID,
  248. mechtypelist);
  249. if (ret != 0) {
  250. *minor_status = ret;
  251. ret = GSS_S_FAILURE;
  252. break;
  253. }
  254. if (first_mech == GSS_C_NO_OID)
  255. first_mech = &supported_mechs->elements[i];
  256. }
  257. if (mechtypelist->len == 0) {
  258. gss_release_oid_set(minor_status, &supported_mechs);
  259. *minor_status = 0;
  260. return GSS_S_BAD_MECH;
  261. }
  262. if (preferred_mech != NULL) {
  263. ret = gss_duplicate_oid(minor_status, first_mech, preferred_mech);
  264. if (ret != GSS_S_COMPLETE)
  265. free_MechTypeList(mechtypelist);
  266. }
  267. gss_release_oid_set(minor_status, &supported_mechs);
  268. return ret;
  269. }