Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/plugins/gssapi/negoextest/main.c
34907 views
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/* plugins/gssapi/negoextest/main.c - GSS test module for NegoEx */
3
/*
4
* Copyright (C) 2019 by the Massachusetts Institute of Technology.
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
*
11
* * Redistributions of source code must retain the above copyright
12
* notice, this list of conditions and the following disclaimer.
13
*
14
* * Redistributions in binary form must reproduce the above copyright
15
* notice, this list of conditions and the following disclaimer in
16
* the documentation and/or other materials provided with the
17
* distribution.
18
*
19
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30
* OF THE POSSIBILITY OF SUCH DAMAGE.
31
*/
32
33
#include "k5-int.h"
34
#include <gssapi/gssapi.h>
35
#include <gssapi/gssapi_ext.h>
36
#include <gssapi/gssapi_alloc.h>
37
38
struct test_context {
39
int initiator;
40
uint8_t hops; /* hops remaining; 0 means established */
41
};
42
43
OM_uint32 KRB5_CALLCONV
44
gss_init_sec_context(OM_uint32 *minor_status,
45
gss_cred_id_t claimant_cred_handle,
46
gss_ctx_id_t *context_handle, gss_name_t target_name,
47
gss_OID mech_type, OM_uint32 req_flags,
48
OM_uint32 time_req,
49
gss_channel_bindings_t input_chan_bindings,
50
gss_buffer_t input_token, gss_OID *actual_mech,
51
gss_buffer_t output_token, OM_uint32 *ret_flags,
52
OM_uint32 *time_rec)
53
{
54
struct test_context *ctx = (struct test_context *)*context_handle;
55
OM_uint32 major;
56
gss_buffer_desc tok;
57
const char *envstr;
58
uint8_t hops, mech_last_octet;
59
60
envstr = getenv("GSS_INIT_BINDING");
61
if (envstr != NULL) {
62
assert(strlen(envstr) > 0);
63
assert(input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS);
64
assert(strlen(envstr) == input_chan_bindings->application_data.length);
65
assert(strcmp((char *)input_chan_bindings->application_data.value,
66
envstr) == 0);
67
}
68
69
if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) {
70
envstr = getenv("HOPS");
71
hops = (envstr != NULL) ? atoi(envstr) : 1;
72
assert(hops > 0);
73
} else if (input_token->length == 4 &&
74
memcmp(input_token->value, "fail", 4) == 0) {
75
*minor_status = 12345;
76
return GSS_S_FAILURE;
77
} else {
78
hops = ((uint8_t *)input_token->value)[0];
79
}
80
81
mech_last_octet = ((uint8_t *)mech_type->elements)[mech_type->length - 1];
82
envstr = getenv("INIT_FAIL");
83
if (envstr != NULL && atoi(envstr) == mech_last_octet)
84
return GSS_S_FAILURE;
85
86
if (ctx == NULL) {
87
ctx = malloc(sizeof(*ctx));
88
assert(ctx != NULL);
89
ctx->initiator = 1;
90
ctx->hops = hops;
91
*context_handle = (gss_ctx_id_t)ctx;
92
} else if (ctx != NULL) {
93
assert(ctx->initiator);
94
ctx->hops--;
95
assert(ctx->hops == hops);
96
}
97
98
if (ctx->hops > 0) {
99
/* Generate a token containing the remaining hop count. */
100
ctx->hops--;
101
tok.value = &ctx->hops;
102
tok.length = 1;
103
major = gss_encapsulate_token(&tok, mech_type, output_token);
104
assert(major == GSS_S_COMPLETE);
105
}
106
107
return (ctx->hops > 0) ? GSS_S_CONTINUE_NEEDED : GSS_S_COMPLETE;
108
}
109
110
OM_uint32 KRB5_CALLCONV
111
gss_accept_sec_context(OM_uint32 *minor_status, gss_ctx_id_t *context_handle,
112
gss_cred_id_t verifier_cred_handle,
113
gss_buffer_t input_token,
114
gss_channel_bindings_t input_chan_bindings,
115
gss_name_t *src_name, gss_OID *mech_type,
116
gss_buffer_t output_token, OM_uint32 *ret_flags,
117
OM_uint32 *time_rec,
118
gss_cred_id_t *delegated_cred_handle)
119
{
120
struct test_context *ctx = (struct test_context *)*context_handle;
121
uint8_t hops, mech_last_octet;
122
const char *envstr;
123
124
envstr = getenv("GSS_ACCEPT_BINDING");
125
if (envstr != NULL) {
126
assert(strlen(envstr) > 0);
127
assert(input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS);
128
assert(strlen(envstr) == input_chan_bindings->application_data.length);
129
assert(strcmp((char *)input_chan_bindings->application_data.value,
130
envstr) == 0);
131
}
132
133
/*
134
* The unwrapped token sits at the end and is just one byte giving the
135
* remaining number of hops. The final octet of the mech encoding should
136
* be just prior to it.
137
*/
138
assert(input_token->length >= 2);
139
hops = ((uint8_t *)input_token->value)[input_token->length - 1];
140
mech_last_octet = ((uint8_t *)input_token->value)[input_token->length - 2];
141
142
envstr = getenv("ACCEPT_FAIL");
143
if (envstr != NULL && atoi(envstr) == mech_last_octet) {
144
output_token->value = gssalloc_strdup("fail");
145
assert(output_token->value != NULL);
146
output_token->length = 4;
147
return GSS_S_FAILURE;
148
}
149
150
if (*context_handle == GSS_C_NO_CONTEXT) {
151
ctx = malloc(sizeof(*ctx));
152
assert(ctx != NULL);
153
ctx->initiator = 0;
154
ctx->hops = hops;
155
*context_handle = (gss_ctx_id_t)ctx;
156
} else {
157
assert(!ctx->initiator);
158
ctx->hops--;
159
assert(ctx->hops == hops);
160
}
161
162
if (ctx->hops > 0) {
163
/* Generate a token containing the remaining hop count. */
164
ctx->hops--;
165
output_token->value = gssalloc_malloc(1);
166
assert(output_token->value != NULL);
167
memcpy(output_token->value, &ctx->hops, 1);
168
output_token->length = 1;
169
}
170
171
return (ctx->hops > 0) ? GSS_S_CONTINUE_NEEDED : GSS_S_COMPLETE;
172
}
173
174
OM_uint32 KRB5_CALLCONV
175
gss_delete_sec_context(OM_uint32 *minor_status, gss_ctx_id_t *context_handle,
176
gss_buffer_t output_token)
177
{
178
free(*context_handle);
179
*context_handle = GSS_C_NO_CONTEXT;
180
return GSS_S_COMPLETE;
181
}
182
183
OM_uint32 KRB5_CALLCONV
184
gss_acquire_cred(OM_uint32 *minor_status, gss_name_t desired_name,
185
OM_uint32 time_req, gss_OID_set desired_mechs,
186
gss_cred_usage_t cred_usage,
187
gss_cred_id_t *output_cred_handle, gss_OID_set *actual_mechs,
188
OM_uint32 *time_rec)
189
{
190
return GSS_S_COMPLETE;
191
}
192
193
OM_uint32 KRB5_CALLCONV
194
gss_acquire_cred_with_password(OM_uint32 *minor_status,
195
const gss_name_t desired_name,
196
const gss_buffer_t password, OM_uint32 time_req,
197
const gss_OID_set desired_mechs,
198
gss_cred_usage_t cred_usage,
199
gss_cred_id_t *output_cred_handle,
200
gss_OID_set *actual_mechs, OM_uint32 *time_rec)
201
{
202
return GSS_S_COMPLETE;
203
}
204
205
OM_uint32 KRB5_CALLCONV
206
gss_release_cred(OM_uint32 *minor_status, gss_cred_id_t *cred_handle)
207
{
208
return GSS_S_COMPLETE;
209
}
210
211
OM_uint32 KRB5_CALLCONV
212
gss_import_name(OM_uint32 *minor_status, gss_buffer_t input_name_buffer,
213
gss_OID input_name_type, gss_name_t *output_name)
214
{
215
static int dummy;
216
217
/*
218
* We don't need to remember anything about names, but we do need to
219
* distinguish them from GSS_C_NO_NAME (to determine the direction of
220
* gss_query_meta_data() and gss_exchange_meta_data()), so assign an
221
* arbitrary data pointer.
222
*/
223
*output_name = (gss_name_t)&dummy;
224
return GSS_S_COMPLETE;
225
}
226
227
OM_uint32 KRB5_CALLCONV
228
gss_release_name(OM_uint32 *minor_status, gss_name_t *input_name)
229
{
230
return GSS_S_COMPLETE;
231
}
232
233
OM_uint32 KRB5_CALLCONV
234
gss_display_status(OM_uint32 *minor_status, OM_uint32 status_value,
235
int status_type, gss_OID mech_type,
236
OM_uint32 *message_context, gss_buffer_t status_string)
237
{
238
if (status_type == GSS_C_MECH_CODE && status_value == 12345) {
239
status_string->value = gssalloc_strdup("failure from acceptor");
240
assert(status_string->value != NULL);
241
status_string->length = strlen(status_string->value);
242
return GSS_S_COMPLETE;
243
}
244
return GSS_S_BAD_STATUS;
245
}
246
247
OM_uint32 KRB5_CALLCONV
248
gssspi_query_meta_data(OM_uint32 *minor_status, gss_const_OID mech_oid,
249
gss_cred_id_t cred_handle, gss_ctx_id_t *context_handle,
250
const gss_name_t targ_name, OM_uint32 req_flags,
251
gss_buffer_t meta_data)
252
{
253
const char *envstr;
254
uint8_t mech_last_octet;
255
int initiator = (targ_name != GSS_C_NO_NAME);
256
257
mech_last_octet = ((uint8_t *)mech_oid->elements)[mech_oid->length - 1];
258
envstr = getenv(initiator ? "INIT_QUERY_FAIL" : "ACCEPT_QUERY_FAIL");
259
if (envstr != NULL && atoi(envstr) == mech_last_octet)
260
return GSS_S_FAILURE;
261
envstr = getenv(initiator ? "INIT_QUERY_NONE" : "ACCEPT_QUERY_NONE");
262
if (envstr != NULL && atoi(envstr) == mech_last_octet)
263
return GSS_S_COMPLETE;
264
265
meta_data->value = gssalloc_strdup("X");
266
meta_data->length = 1;
267
return GSS_S_COMPLETE;
268
}
269
270
OM_uint32 KRB5_CALLCONV
271
gssspi_exchange_meta_data(OM_uint32 *minor_status, gss_const_OID mech_oid,
272
gss_cred_id_t cred_handle,
273
gss_ctx_id_t *context_handle,
274
const gss_name_t targ_name, OM_uint32 req_flags,
275
gss_const_buffer_t meta_data)
276
{
277
const char *envstr;
278
uint8_t mech_last_octet;
279
int initiator = (targ_name != GSS_C_NO_NAME);
280
281
mech_last_octet = ((uint8_t *)mech_oid->elements)[mech_oid->length - 1];
282
envstr = getenv(initiator ? "INIT_EXCHANGE_FAIL" : "ACCEPT_EXCHANGE_FAIL");
283
if (envstr != NULL && atoi(envstr) == mech_last_octet)
284
return GSS_S_FAILURE;
285
286
assert(meta_data->length == 1 && memcmp(meta_data->value, "X", 1) == 0);
287
return GSS_S_COMPLETE;
288
}
289
290
OM_uint32 KRB5_CALLCONV
291
gssspi_query_mechanism_info(OM_uint32 *minor_status, gss_const_OID mech_oid,
292
unsigned char auth_scheme[16])
293
{
294
/* Copy the mech OID encoding and right-pad it with zeros. */
295
memset(auth_scheme, 0, 16);
296
assert(mech_oid->length <= 16);
297
memcpy(auth_scheme, mech_oid->elements, mech_oid->length);
298
return GSS_S_COMPLETE;
299
}
300
301
OM_uint32 KRB5_CALLCONV
302
gss_inquire_sec_context_by_oid(OM_uint32 *minor_status,
303
const gss_ctx_id_t context_handle,
304
const gss_OID desired_object,
305
gss_buffer_set_t *data_set)
306
{
307
struct test_context *ctx = (struct test_context *)context_handle;
308
OM_uint32 major;
309
uint8_t keybytes[32] = { 0 };
310
uint8_t typebytes[4];
311
gss_buffer_desc key, type;
312
const char *envstr;
313
int ask_verify;
314
315
if (gss_oid_equal(desired_object, GSS_C_INQ_NEGOEX_KEY))
316
ask_verify = 0;
317
else if (gss_oid_equal(desired_object, GSS_C_INQ_NEGOEX_VERIFY_KEY))
318
ask_verify = 1;
319
else
320
return GSS_S_UNAVAILABLE;
321
322
/*
323
* By default, make a key available only if the context is established.
324
* This can be overridden to "always", "init-always", "accept-always",
325
* or "never".
326
*/
327
envstr = getenv("KEY");
328
if (envstr != NULL && strcmp(envstr, "never") == 0) {
329
return GSS_S_UNAVAILABLE;
330
} else if (ctx->hops > 0) {
331
if (envstr == NULL)
332
return GSS_S_UNAVAILABLE;
333
else if (strcmp(envstr, "init-always") == 0 && !ctx->initiator)
334
return GSS_S_UNAVAILABLE;
335
else if (strcmp(envstr, "accept-always") == 0 && ctx->initiator)
336
return GSS_S_UNAVAILABLE;
337
}
338
339
/* Perturb the key so that each side's verifier key is equal to the other's
340
* checksum key. */
341
keybytes[0] = ask_verify ^ ctx->initiator;
342
343
/* Supply an all-zeros aes256-sha1 negoex key. */
344
if (gss_oid_equal(desired_object, GSS_C_INQ_NEGOEX_KEY) ||
345
gss_oid_equal(desired_object, GSS_C_INQ_NEGOEX_VERIFY_KEY)) {
346
store_32_le(ENCTYPE_AES256_CTS_HMAC_SHA1_96, typebytes);
347
key.value = keybytes;
348
key.length = sizeof(keybytes);
349
type.value = typebytes;
350
type.length = sizeof(typebytes);
351
major = gss_add_buffer_set_member(minor_status, &key, data_set);
352
if (major != GSS_S_COMPLETE)
353
return major;
354
return gss_add_buffer_set_member(minor_status, &type, data_set);
355
}
356
357
return GSS_S_UNAVAILABLE;
358
}
359
360