2 * Copyright (c) 2004, PADL Software Pty Ltd.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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.
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.
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
33 #include "spnego_locl.h"
36 * Apparently Microsoft got the OID wrong, and used
37 * 1.2.840.48018.1.2.2 instead. We need both this and
38 * the correct Kerberos OID here in order to deal with
39 * this. Because this is manifest in SPNEGO only I'd
40 * prefer to deal with this here rather than inside the
43 gss_OID_desc _gss_spnego_mskrb_mechanism_oid_desc
=
44 {9, rk_UNCONST("\x2a\x86\x48\x82\xf7\x12\x01\x02\x02")};
46 gss_OID_desc _gss_spnego_krb5_mechanism_oid_desc
=
47 {9, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02")};
50 * Allocate a SPNEGO context handle
52 OM_uint32 GSSAPI_CALLCONV
53 _gss_spnego_alloc_sec_context (OM_uint32
* minor_status
,
54 gss_ctx_id_t
*context_handle
)
58 ctx
= calloc(1, sizeof(*ctx
));
60 *minor_status
= ENOMEM
;
64 ctx
->initiator_mech_types
.len
= 0;
65 ctx
->initiator_mech_types
.val
= NULL
;
66 ctx
->preferred_mech_type
= GSS_C_NO_OID
;
67 ctx
->negotiated_mech_type
= GSS_C_NO_OID
;
68 ctx
->negotiated_ctx_id
= GSS_C_NO_CONTEXT
;
71 * Cache these so we can return them before returning
72 * GSS_S_COMPLETE, even if the mechanism has itself
76 ctx
->mech_time_rec
= 0;
77 ctx
->mech_src_name
= GSS_C_NO_NAME
;
82 ctx
->verified_mic
= 0;
84 HEIMDAL_MUTEX_init(&ctx
->ctx_id_mutex
);
86 *context_handle
= (gss_ctx_id_t
)ctx
;
88 return GSS_S_COMPLETE
;
92 * Free a SPNEGO context handle. The caller must have acquired
93 * the lock before this is called.
95 OM_uint32 GSSAPI_CALLCONV _gss_spnego_internal_delete_sec_context
96 (OM_uint32
*minor_status
,
97 gss_ctx_id_t
*context_handle
,
98 gss_buffer_t output_token
102 OM_uint32 ret
, minor
;
106 if (context_handle
== NULL
) {
107 return GSS_S_NO_CONTEXT
;
110 if (output_token
!= GSS_C_NO_BUFFER
) {
111 output_token
->length
= 0;
112 output_token
->value
= NULL
;
115 ctx
= (gssspnego_ctx
)*context_handle
;
116 *context_handle
= GSS_C_NO_CONTEXT
;
119 return GSS_S_NO_CONTEXT
;
122 if (ctx
->initiator_mech_types
.val
!= NULL
)
123 free_MechTypeList(&ctx
->initiator_mech_types
);
125 gss_release_oid(&minor
, &ctx
->preferred_mech_type
);
126 ctx
->negotiated_mech_type
= GSS_C_NO_OID
;
128 gss_release_name(&minor
, &ctx
->target_name
);
129 gss_release_name(&minor
, &ctx
->mech_src_name
);
131 if (ctx
->negotiated_ctx_id
!= GSS_C_NO_CONTEXT
) {
132 ret
= gss_delete_sec_context(minor_status
,
133 &ctx
->negotiated_ctx_id
,
135 ctx
->negotiated_ctx_id
= GSS_C_NO_CONTEXT
;
137 ret
= GSS_S_COMPLETE
;
140 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
141 HEIMDAL_MUTEX_destroy(&ctx
->ctx_id_mutex
);
149 * For compatability with the Windows SPNEGO implementation, the
150 * default is to ignore the mechListMIC unless CFX is used and
151 * a non-preferred mechanism was negotiated
154 OM_uint32 GSSAPI_CALLCONV
155 _gss_spnego_require_mechlist_mic(OM_uint32
*minor_status
,
159 gss_buffer_set_t buffer_set
= GSS_C_NO_BUFFER_SET
;
166 return GSS_S_COMPLETE
;
169 if (ctx
->require_mic
) {
170 /* Acceptor requested it: mandatory to honour */
172 return GSS_S_COMPLETE
;
176 * Check whether peer indicated implicit support for updated SPNEGO
177 * (eg. in the Kerberos case by using CFX)
179 if (gss_inquire_sec_context_by_oid(&minor
, ctx
->negotiated_ctx_id
,
180 GSS_C_PEER_HAS_UPDATED_SPNEGO
,
181 &buffer_set
) == GSS_S_COMPLETE
) {
183 gss_release_buffer_set(&minor
, &buffer_set
);
186 /* Safe-to-omit MIC rules follow */
188 if (gss_oid_equal(ctx
->negotiated_mech_type
, ctx
->preferred_mech_type
)) {
190 } else if (gss_oid_equal(ctx
->negotiated_mech_type
, &_gss_spnego_krb5_mechanism_oid_desc
) &&
191 gss_oid_equal(ctx
->preferred_mech_type
, &_gss_spnego_mskrb_mechanism_oid_desc
)) {
196 return GSS_S_COMPLETE
;
200 add_mech_type(gss_OID mech_type
,
201 int includeMSCompatOID
,
202 MechTypeList
*mechtypelist
)
207 if (gss_oid_equal(mech_type
, GSS_SPNEGO_MECHANISM
))
210 if (includeMSCompatOID
&&
211 gss_oid_equal(mech_type
, &_gss_spnego_krb5_mechanism_oid_desc
)) {
212 ret
= der_get_oid(_gss_spnego_mskrb_mechanism_oid_desc
.elements
,
213 _gss_spnego_mskrb_mechanism_oid_desc
.length
,
218 ret
= add_MechTypeList(mechtypelist
, &mech
);
219 free_MechType(&mech
);
223 ret
= der_get_oid(mech_type
->elements
, mech_type
->length
, &mech
, NULL
);
226 ret
= add_MechTypeList(mechtypelist
, &mech
);
227 free_MechType(&mech
);
232 OM_uint32 GSSAPI_CALLCONV
233 _gss_spnego_indicate_mechtypelist (OM_uint32
*minor_status
,
234 gss_name_t target_name
,
235 OM_uint32 (*func
)(gss_name_t
, gss_OID
),
236 int includeMSCompatOID
,
237 gss_const_cred_id_t cred_handle
,
238 MechTypeList
*mechtypelist
,
239 gss_OID
*preferred_mech
)
241 gss_OID_set supported_mechs
= GSS_C_NO_OID_SET
;
242 gss_OID first_mech
= GSS_C_NO_OID
;
246 mechtypelist
->len
= 0;
247 mechtypelist
->val
= NULL
;
250 ret
= gss_inquire_cred(minor_status
,
257 ret
= gss_indicate_mechs(minor_status
, &supported_mechs
);
260 if (ret
!= GSS_S_COMPLETE
) {
264 if (supported_mechs
->count
== 0) {
265 *minor_status
= ENOENT
;
266 gss_release_oid_set(minor_status
, &supported_mechs
);
267 return GSS_S_FAILURE
;
270 ret
= (*func
)(target_name
, GSS_KRB5_MECHANISM
);
271 if (ret
== GSS_S_COMPLETE
) {
272 ret
= add_mech_type(GSS_KRB5_MECHANISM
,
276 first_mech
= GSS_KRB5_MECHANISM
;
278 ret
= GSS_S_COMPLETE
;
280 for (i
= 0; i
< supported_mechs
->count
; i
++) {
282 if (gss_oid_equal(&supported_mechs
->elements
[i
], GSS_SPNEGO_MECHANISM
))
284 if (gss_oid_equal(&supported_mechs
->elements
[i
], GSS_KRB5_MECHANISM
))
287 subret
= (*func
)(target_name
, &supported_mechs
->elements
[i
]);
288 if (subret
!= GSS_S_COMPLETE
)
291 ret
= add_mech_type(&supported_mechs
->elements
[i
],
299 if (first_mech
== GSS_C_NO_OID
)
300 first_mech
= &supported_mechs
->elements
[i
];
303 if (mechtypelist
->len
== 0) {
304 gss_release_oid_set(minor_status
, &supported_mechs
);
306 return GSS_S_BAD_MECH
;
309 if (preferred_mech
!= NULL
) {
310 ret
= gss_duplicate_oid(minor_status
, first_mech
, preferred_mech
);
311 if (ret
!= GSS_S_COMPLETE
)
312 free_MechTypeList(mechtypelist
);
314 gss_release_oid_set(minor_status
, &supported_mechs
);