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 */
290 *minor = GSSEAP_MISSING_REQUIRED_EXT;
291 major = GSS_S_UNAVAILABLE;
296 /* Check we processed all critical extensions */
297 for (i = 0; i < extensions->count; i++) {
298 if ((types[i] & EXT_FLAG_CRITICAL) &&
299 (types[i] & EXT_FLAG_VERIFIED) == 0) {
300 *minor = GSSEAP_CRIT_EXT_UNAVAILABLE;
301 major = GSS_S_UNAVAILABLE;
307 major = GSS_S_COMPLETE;
310 gss_release_buffer_set(&tmpMinor, &extensions);
318 gssEapVerifyExtensions(OM_uint32 *minor,
321 gss_channel_bindings_t chanBindings,
322 const gss_buffer_t buffer)
325 const struct gss_eap_extension_provider *exts;
327 if (CTX_IS_INITIATOR(ctx)) {
328 exts = eapGssAcceptExtensions;
329 nexts = sizeof(eapGssAcceptExtensions) / sizeof(eapGssAcceptExtensions[0]);
331 exts = eapGssInitExtensions;
332 nexts = sizeof(eapGssInitExtensions) / sizeof(eapGssInitExtensions[0]);
335 return verifyExtensions(minor, cred, ctx, exts, nexts, chanBindings, buffer);
339 encodeExtensions(OM_uint32 *minor,
340 gss_buffer_set_t extensions,
344 OM_uint32 major, tmpMinor;
345 size_t required = 0, i;
348 buffer->value = NULL;
351 if (extensions != GSS_C_NO_BUFFER_SET) {
352 for (i = 0; i < extensions->count; i++) {
353 required += 8 + extensions->elements[i].length;
358 * We must always return a non-NULL token otherwise the calling state
359 * machine assumes we are finished. Hence care in case malloc(0) does
362 buffer->value = GSSEAP_MALLOC(required ? required : 1);
363 if (buffer->value == NULL) {
365 major = GSS_S_FAILURE;
369 buffer->length = required;
370 p = (unsigned char *)buffer->value;
372 if (extensions != GSS_C_NO_BUFFER_SET) {
373 for (i = 0; i < extensions->count; i++) {
374 gss_buffer_t extension = &extensions->elements[i];
376 assert((types[i] & EXT_FLAG_VERIFIED) == 0); /* private flag */
379 * Extensions are encoded as type-length-value, where the upper
380 * bit of the type indicates criticality.
382 store_uint32_be(types[i], &p[0]);
383 store_uint32_be(extension->length, &p[4]);
384 memcpy(&p[8], extension->value, extension->length);
386 p += 8 + extension->length;
390 assert(p == (unsigned char *)buffer->value + required);
391 assert(buffer->value != NULL);
394 if (GSS_ERROR(major)) {
395 gss_release_buffer(&tmpMinor, buffer);
402 decodeExtensions(OM_uint32 *minor,
403 const gss_buffer_t buffer,
404 gss_buffer_set_t *pExtensions,
407 OM_uint32 major, tmpMinor;
408 gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
409 OM_uint32 *types = NULL;
413 *pExtensions = GSS_C_NO_BUFFER_SET;
416 major = gss_create_empty_buffer_set(minor, &extensions);
417 if (GSS_ERROR(major))
420 if (buffer->length == 0) {
421 major = GSS_S_COMPLETE;
425 p = (unsigned char *)buffer->value;
426 remain = buffer->length;
430 gss_buffer_desc extension;
433 major = GSS_S_DEFECTIVE_TOKEN;
437 ntypes = GSSEAP_REALLOC(types,
438 (extensions->count + 1) * sizeof(OM_uint32));
439 if (ntypes == NULL) {
441 major = GSS_S_FAILURE;
446 types[extensions->count] = load_uint32_be(&p[0]);
447 extension.length = load_uint32_be(&p[4]);
449 if (remain < 8 + extension.length) {
450 major = GSS_S_DEFECTIVE_TOKEN;
453 extension.value = &p[8];
455 major = gss_add_buffer_set_member(minor, &extension, &extensions);
456 if (GSS_ERROR(major))
459 p += 8 + extension.length;
460 remain -= 8 + extension.length;
461 } while (remain != 0);
464 if (GSS_ERROR(major)) {
465 gss_release_buffer_set(&tmpMinor, &extensions);
469 *pExtensions = extensions;