Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/lib/gssapi/spnego/compat.c
34907 views
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
33
#include "spnego_locl.h"
34
35
/*
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
41
* Kerberos mechanism.
42
*/
43
gss_OID_desc _gss_spnego_mskrb_mechanism_oid_desc =
44
{9, rk_UNCONST("\x2a\x86\x48\x82\xf7\x12\x01\x02\x02")};
45
46
gss_OID_desc _gss_spnego_krb5_mechanism_oid_desc =
47
{9, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02")};
48
49
/*
50
* Allocate a SPNEGO context handle
51
*/
52
OM_uint32 GSSAPI_CALLCONV
53
_gss_spnego_alloc_sec_context (OM_uint32 * minor_status,
54
gss_ctx_id_t *context_handle)
55
{
56
gssspnego_ctx ctx;
57
58
ctx = calloc(1, sizeof(*ctx));
59
if (ctx == NULL) {
60
*minor_status = ENOMEM;
61
return GSS_S_FAILURE;
62
}
63
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;
69
70
/*
71
* Cache these so we can return them before returning
72
* GSS_S_COMPLETE, even if the mechanism has itself
73
* completed earlier
74
*/
75
ctx->mech_flags = 0;
76
ctx->mech_time_rec = 0;
77
ctx->mech_src_name = GSS_C_NO_NAME;
78
79
ctx->open = 0;
80
ctx->local = 0;
81
ctx->require_mic = 0;
82
ctx->verified_mic = 0;
83
84
HEIMDAL_MUTEX_init(&ctx->ctx_id_mutex);
85
86
*context_handle = (gss_ctx_id_t)ctx;
87
88
return GSS_S_COMPLETE;
89
}
90
91
/*
92
* Free a SPNEGO context handle. The caller must have acquired
93
* the lock before this is called.
94
*/
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
99
)
100
{
101
gssspnego_ctx ctx;
102
OM_uint32 ret, minor;
103
104
*minor_status = 0;
105
106
if (context_handle == NULL) {
107
return GSS_S_NO_CONTEXT;
108
}
109
110
if (output_token != GSS_C_NO_BUFFER) {
111
output_token->length = 0;
112
output_token->value = NULL;
113
}
114
115
ctx = (gssspnego_ctx)*context_handle;
116
*context_handle = GSS_C_NO_CONTEXT;
117
118
if (ctx == NULL) {
119
return GSS_S_NO_CONTEXT;
120
}
121
122
if (ctx->initiator_mech_types.val != NULL)
123
free_MechTypeList(&ctx->initiator_mech_types);
124
125
gss_release_oid(&minor, &ctx->preferred_mech_type);
126
ctx->negotiated_mech_type = GSS_C_NO_OID;
127
128
gss_release_name(&minor, &ctx->target_name);
129
gss_release_name(&minor, &ctx->mech_src_name);
130
131
if (ctx->negotiated_ctx_id != GSS_C_NO_CONTEXT) {
132
ret = gss_delete_sec_context(minor_status,
133
&ctx->negotiated_ctx_id,
134
output_token);
135
ctx->negotiated_ctx_id = GSS_C_NO_CONTEXT;
136
} else {
137
ret = GSS_S_COMPLETE;
138
}
139
140
HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
141
HEIMDAL_MUTEX_destroy(&ctx->ctx_id_mutex);
142
143
free(ctx);
144
145
return ret;
146
}
147
148
/*
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
152
*/
153
154
OM_uint32 GSSAPI_CALLCONV
155
_gss_spnego_require_mechlist_mic(OM_uint32 *minor_status,
156
gssspnego_ctx ctx,
157
int *require_mic)
158
{
159
gss_buffer_set_t buffer_set = GSS_C_NO_BUFFER_SET;
160
OM_uint32 minor;
161
162
*minor_status = 0;
163
*require_mic = 0;
164
165
if (ctx == NULL) {
166
return GSS_S_COMPLETE;
167
}
168
169
if (ctx->require_mic) {
170
/* Acceptor requested it: mandatory to honour */
171
*require_mic = 1;
172
return GSS_S_COMPLETE;
173
}
174
175
/*
176
* Check whether peer indicated implicit support for updated SPNEGO
177
* (eg. in the Kerberos case by using CFX)
178
*/
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) {
182
*require_mic = 1;
183
gss_release_buffer_set(&minor, &buffer_set);
184
}
185
186
/* Safe-to-omit MIC rules follow */
187
if (*require_mic) {
188
if (gss_oid_equal(ctx->negotiated_mech_type, ctx->preferred_mech_type)) {
189
*require_mic = 0;
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)) {
192
*require_mic = 0;
193
}
194
}
195
196
return GSS_S_COMPLETE;
197
}
198
199
static int
200
add_mech_type(gss_OID mech_type,
201
int includeMSCompatOID,
202
MechTypeList *mechtypelist)
203
{
204
MechType mech;
205
int ret;
206
207
if (gss_oid_equal(mech_type, GSS_SPNEGO_MECHANISM))
208
return 0;
209
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,
214
&mech,
215
NULL);
216
if (ret)
217
return ret;
218
ret = add_MechTypeList(mechtypelist, &mech);
219
free_MechType(&mech);
220
if (ret)
221
return ret;
222
}
223
ret = der_get_oid(mech_type->elements, mech_type->length, &mech, NULL);
224
if (ret)
225
return ret;
226
ret = add_MechTypeList(mechtypelist, &mech);
227
free_MechType(&mech);
228
return ret;
229
}
230
231
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
const gss_cred_id_t cred_handle,
238
MechTypeList *mechtypelist,
239
gss_OID *preferred_mech)
240
{
241
gss_OID_set supported_mechs = GSS_C_NO_OID_SET;
242
gss_OID first_mech = GSS_C_NO_OID;
243
OM_uint32 ret;
244
size_t i;
245
246
mechtypelist->len = 0;
247
mechtypelist->val = NULL;
248
249
if (cred_handle) {
250
ret = gss_inquire_cred(minor_status,
251
cred_handle,
252
NULL,
253
NULL,
254
NULL,
255
&supported_mechs);
256
} else {
257
ret = gss_indicate_mechs(minor_status, &supported_mechs);
258
}
259
260
if (ret != GSS_S_COMPLETE) {
261
return ret;
262
}
263
264
if (supported_mechs->count == 0) {
265
*minor_status = ENOENT;
266
gss_release_oid_set(minor_status, &supported_mechs);
267
return GSS_S_FAILURE;
268
}
269
270
ret = (*func)(target_name, GSS_KRB5_MECHANISM);
271
if (ret == GSS_S_COMPLETE) {
272
ret = add_mech_type(GSS_KRB5_MECHANISM,
273
includeMSCompatOID,
274
mechtypelist);
275
if (!GSS_ERROR(ret))
276
first_mech = GSS_KRB5_MECHANISM;
277
}
278
ret = GSS_S_COMPLETE;
279
280
for (i = 0; i < supported_mechs->count; i++) {
281
OM_uint32 subret;
282
if (gss_oid_equal(&supported_mechs->elements[i], GSS_SPNEGO_MECHANISM))
283
continue;
284
if (gss_oid_equal(&supported_mechs->elements[i], GSS_KRB5_MECHANISM))
285
continue;
286
287
subret = (*func)(target_name, &supported_mechs->elements[i]);
288
if (subret != GSS_S_COMPLETE)
289
continue;
290
291
ret = add_mech_type(&supported_mechs->elements[i],
292
includeMSCompatOID,
293
mechtypelist);
294
if (ret != 0) {
295
*minor_status = ret;
296
ret = GSS_S_FAILURE;
297
break;
298
}
299
if (first_mech == GSS_C_NO_OID)
300
first_mech = &supported_mechs->elements[i];
301
}
302
303
if (mechtypelist->len == 0) {
304
gss_release_oid_set(minor_status, &supported_mechs);
305
*minor_status = 0;
306
return GSS_S_BAD_MECH;
307
}
308
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);
313
}
314
gss_release_oid_set(minor_status, &supported_mechs);
315
316
return ret;
317
}
318
319