2 * Copyright (c) 2010, JANET(UK)
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 JANET(UK) 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND 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 THE COPYRIGHT HOLDER 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 "gssapiP_eap.h"
36 encodeExtensions(OM_uint32 *minor,
37 gss_buffer_set_t extensions,
42 decodeExtensions(OM_uint32 *minor,
43 const gss_buffer_t buffer,
44 gss_buffer_set_t *pExtensions,
48 * Initiator extensions
51 makeGssChannelBindings(OM_uint32 *minor,
54 gss_channel_bindings_t chanBindings,
55 gss_buffer_t outputToken)
58 gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER;
60 if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS)
61 buffer = chanBindings->application_data;
63 major = gssEapWrap(minor, ctx, TRUE, GSS_C_QOP_DEFAULT,
64 &buffer, NULL, outputToken);
68 return GSS_S_COMPLETE;
72 verifyGssChannelBindings(OM_uint32 *minor,
75 gss_channel_bindings_t chanBindings,
76 gss_buffer_t inputToken)
78 OM_uint32 major, tmpMinor;
79 gss_iov_buffer_desc iov[2];
81 iov[0].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE;
82 iov[0].buffer.length = 0;
83 iov[0].buffer.value = NULL;
85 iov[1].type = GSS_IOV_BUFFER_TYPE_STREAM;
86 iov[1].buffer = *inputToken;
88 major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
89 iov, 2, TOK_TYPE_WRAP);
93 if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS &&
94 !bufferEqual(&iov[0].buffer, &chanBindings->application_data)) {
95 major = GSS_S_BAD_BINDINGS;
97 major = GSS_S_COMPLETE;
100 gss_release_buffer(&tmpMinor, &iov[0].buffer);
105 static struct gss_eap_extension_provider
106 eapGssInitExtensions[] = {
108 EXT_TYPE_GSS_CHANNEL_BINDINGS,
111 makeGssChannelBindings,
112 verifyGssChannelBindings
117 * Acceptor extensions
120 makeReauthCreds(OM_uint32 *minor,
123 gss_channel_bindings_t chanBindings,
124 gss_buffer_t outputToken)
126 OM_uint32 major = GSS_S_UNAVAILABLE;
128 #ifdef GSSEAP_ENABLE_REAUTH
130 * If we're built with fast reauthentication enabled, then
131 * fabricate a ticket from the initiator to ourselves.
133 major = gssEapMakeReauthCreds(minor, ctx, cred, outputToken);
140 verifyReauthCreds(OM_uint32 *minor,
143 gss_channel_bindings_t chanBindings,
144 gss_buffer_t inputToken)
146 OM_uint32 major = GSS_S_UNAVAILABLE;
148 #ifdef GSSEAP_ENABLE_REAUTH
149 major = gssEapStoreReauthCreds(minor, ctx, cred, inputToken);
155 static struct gss_eap_extension_provider
156 eapGssAcceptExtensions[] = {
158 EXT_TYPE_REAUTH_CREDS,
167 makeExtensions(OM_uint32 *minor,
170 const struct gss_eap_extension_provider *exts,
172 gss_channel_bindings_t chanBindings,
175 OM_uint32 major, tmpMinor;
177 gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
180 assert(buffer != GSS_C_NO_BUFFER);
183 buffer->value = NULL;
185 types = GSSEAP_CALLOC(nexts, sizeof(OM_uint32));
188 major = GSS_S_FAILURE;
192 for (i = 0, j = 0; i < nexts; i++) {
193 const struct gss_eap_extension_provider *ext = &exts[i];
194 gss_buffer_desc extension = GSS_C_EMPTY_BUFFER;
196 types[j] = ext->type;
198 types[j] |= EXT_FLAG_CRITICAL;
200 major = ext->make(minor, cred, ctx, chanBindings, &extension);
201 if (GSS_ERROR(major)) {
208 major = gss_add_buffer_set_member(minor, &extension, &extensions);
209 if (GSS_ERROR(major))
215 assert(j == (extensions == GSS_C_NO_BUFFER_SET ? 0 : extensions->count));
217 major = encodeExtensions(minor, extensions, types, buffer);
218 if (GSS_ERROR(major))
222 gss_release_buffer_set(&tmpMinor, &extensions);
230 gssEapMakeExtensions(OM_uint32 *minor,
233 gss_channel_bindings_t chanBindings,
237 const struct gss_eap_extension_provider *exts;
239 if (CTX_IS_INITIATOR(ctx)) {
240 exts = eapGssInitExtensions;
241 nexts = sizeof(eapGssInitExtensions) / sizeof(eapGssInitExtensions[0]);
243 exts = eapGssAcceptExtensions;
244 nexts = sizeof(eapGssAcceptExtensions) / sizeof(eapGssAcceptExtensions[0]);
247 return makeExtensions(minor, cred, ctx, exts, nexts, chanBindings, buffer);
251 verifyExtensions(OM_uint32 *minor,
254 const struct gss_eap_extension_provider *exts,
256 gss_channel_bindings_t chanBindings,
257 const gss_buffer_t buffer)
259 OM_uint32 major, tmpMinor;
260 gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
261 OM_uint32 *types = NULL;
264 major = decodeExtensions(minor, buffer, &extensions, &types);
265 if (GSS_ERROR(major))
268 for (i = 0; i < nexts; i++) {
269 const struct gss_eap_extension_provider *ext = &exts[i];
270 gss_buffer_t extension = GSS_C_NO_BUFFER;
273 for (j = 0; j < extensions->count; j++) {
274 if ((types[j] & EXT_TYPE_MASK) == ext->type) {
275 extension = &extensions->elements[j];
280 if (extension != GSS_C_NO_BUFFER) {
281 /* Process extension and mark as verified */
282 major = ext->verify(minor, cred, ctx, chanBindings,
283 &extensions->elements[j]);
284 if (GSS_ERROR(major))
287 types[j] |= EXT_FLAG_VERIFIED;
288 } else if (ext->required) {
289 /* Required extension missing */
291 major = GSS_S_UNAVAILABLE;
292 gssEapSaveStatusInfo(*minor,
293 "Missing required GSS EAP extension %08x",
299 /* Check we processed all critical extensions */
300 for (i = 0; i < extensions->count; i++) {
301 if ((types[i] & EXT_FLAG_CRITICAL) &&
302 (types[i] & EXT_FLAG_VERIFIED) == 0) {
304 major = GSS_S_UNAVAILABLE;
305 gssEapSaveStatusInfo(*minor,
306 "Received unknown critical GSS EAP extension %08x",
307 (types[i] & EXT_TYPE_MASK));
313 major = GSS_S_COMPLETE;
316 gss_release_buffer_set(&tmpMinor, &extensions);
324 gssEapVerifyExtensions(OM_uint32 *minor,
327 gss_channel_bindings_t chanBindings,
328 const gss_buffer_t buffer)
331 const struct gss_eap_extension_provider *exts;
333 if (CTX_IS_INITIATOR(ctx)) {
334 exts = eapGssAcceptExtensions;
335 nexts = sizeof(eapGssAcceptExtensions) / sizeof(eapGssAcceptExtensions[0]);
337 exts = eapGssInitExtensions;
338 nexts = sizeof(eapGssInitExtensions) / sizeof(eapGssInitExtensions[0]);
341 return verifyExtensions(minor, cred, ctx, exts, nexts, chanBindings, buffer);
345 encodeExtensions(OM_uint32 *minor,
346 gss_buffer_set_t extensions,
350 OM_uint32 major, tmpMinor;
351 size_t required = 0, i;
354 buffer->value = NULL;
357 if (extensions != GSS_C_NO_BUFFER_SET) {
358 for (i = 0; i < extensions->count; i++) {
359 required += 8 + extensions->elements[i].length;
364 * We must always return a non-NULL token otherwise the calling state
365 * machine assumes we are finished. Hence care in case malloc(0) does
368 buffer->value = GSSEAP_MALLOC(required ? required : 1);
369 if (buffer->value == NULL) {
371 major = GSS_S_FAILURE;
375 buffer->length = required;
376 p = (unsigned char *)buffer->value;
378 if (extensions != GSS_C_NO_BUFFER_SET) {
379 for (i = 0; i < extensions->count; i++) {
380 gss_buffer_t extension = &extensions->elements[i];
382 assert((types[i] & EXT_FLAG_VERIFIED) == 0); /* private flag */
385 * Extensions are encoded as type-length-value, where the upper
386 * bit of the type indicates criticality.
388 store_uint32_be(types[i], &p[0]);
389 store_uint32_be(extension->length, &p[4]);
390 memcpy(&p[8], extension->value, extension->length);
392 p += 8 + extension->length;
396 assert(p == (unsigned char *)buffer->value + required);
397 assert(buffer->value != NULL);
400 if (GSS_ERROR(major)) {
401 gss_release_buffer(&tmpMinor, buffer);
408 decodeExtensions(OM_uint32 *minor,
409 const gss_buffer_t buffer,
410 gss_buffer_set_t *pExtensions,
413 OM_uint32 major, tmpMinor;
414 gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
415 OM_uint32 *types = NULL;
419 *pExtensions = GSS_C_NO_BUFFER_SET;
422 major = gss_create_empty_buffer_set(minor, &extensions);
423 if (GSS_ERROR(major))
426 if (buffer->length == 0) {
427 major = GSS_S_COMPLETE;
431 p = (unsigned char *)buffer->value;
432 remain = buffer->length;
436 gss_buffer_desc extension;
439 major = GSS_S_DEFECTIVE_TOKEN;
443 ntypes = GSSEAP_REALLOC(types,
444 (extensions->count + 1) * sizeof(OM_uint32));
445 if (ntypes == NULL) {
447 major = GSS_S_FAILURE;
452 types[extensions->count] = load_uint32_be(&p[0]);
453 extension.length = load_uint32_be(&p[4]);
455 if (remain < 8 + extension.length) {
456 major = GSS_S_DEFECTIVE_TOKEN;
459 extension.value = &p[8];
461 major = gss_add_buffer_set_member(minor, &extension, &extensions);
462 if (GSS_ERROR(major))
465 p += 8 + extension.length;
466 remain -= 8 + extension.length;
467 } while (remain != 0);
470 if (GSS_ERROR(major)) {
471 gss_release_buffer_set(&tmpMinor, &extensions);
475 *pExtensions = extensions;