2 * Copyright (c) 2011, 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
34 * Extension token support.
37 #include "gssapiP_eap.h"
40 encodeExtensions(OM_uint32 *minor,
41 gss_buffer_set_t extensions,
46 decodeExtensions(OM_uint32 *minor,
47 const gss_buffer_t buffer,
48 gss_buffer_set_t *pExtensions,
52 * Initiator extensions
55 makeGssChannelBindings(OM_uint32 *minor,
58 gss_channel_bindings_t chanBindings,
59 gss_buffer_t outputToken)
62 gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER;
64 if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS)
65 buffer = chanBindings->application_data;
67 major = gssEapWrap(minor, ctx, TRUE, GSS_C_QOP_DEFAULT,
68 &buffer, NULL, outputToken);
72 return GSS_S_COMPLETE;
76 verifyGssChannelBindings(OM_uint32 *minor,
79 gss_channel_bindings_t chanBindings,
80 gss_buffer_t inputToken)
82 OM_uint32 major, tmpMinor;
83 gss_iov_buffer_desc iov[2];
85 iov[0].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE;
86 iov[0].buffer.length = 0;
87 iov[0].buffer.value = NULL;
89 iov[1].type = GSS_IOV_BUFFER_TYPE_STREAM;
90 iov[1].buffer = *inputToken;
92 major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
93 iov, 2, TOK_TYPE_WRAP);
95 return GSS_S_BAD_BINDINGS;
97 if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS &&
98 !bufferEqual(&iov[0].buffer, &chanBindings->application_data)) {
99 major = GSS_S_BAD_BINDINGS;
100 *minor = GSSEAP_BINDINGS_MISMATCH;
102 major = GSS_S_COMPLETE;
105 gss_release_buffer(&tmpMinor, &iov[0].buffer);
110 static struct gss_eap_extension_provider
111 eapGssInitExtensions[] = {
113 EXT_TYPE_GSS_CHANNEL_BINDINGS,
116 makeGssChannelBindings,
117 verifyGssChannelBindings
122 * Acceptor extensions
125 makeReauthCreds(OM_uint32 *minor,
128 gss_channel_bindings_t chanBindings,
129 gss_buffer_t outputToken)
131 OM_uint32 major = GSS_S_UNAVAILABLE;
133 #ifdef GSSEAP_ENABLE_REAUTH
135 * If we're built with fast reauthentication enabled, then
136 * fabricate a ticket from the initiator to ourselves.
138 major = gssEapMakeReauthCreds(minor, ctx, cred, outputToken);
145 verifyReauthCreds(OM_uint32 *minor,
148 gss_channel_bindings_t chanBindings,
149 gss_buffer_t inputToken)
151 OM_uint32 major = GSS_S_UNAVAILABLE;
153 #ifdef GSSEAP_ENABLE_REAUTH
154 major = gssEapStoreReauthCreds(minor, ctx, cred, inputToken);
160 static struct gss_eap_extension_provider
161 eapGssAcceptExtensions[] = {
163 EXT_TYPE_REAUTH_CREDS,
172 makeExtensions(OM_uint32 *minor,
175 const struct gss_eap_extension_provider *exts,
177 gss_channel_bindings_t chanBindings,
180 OM_uint32 major, tmpMinor;
182 gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
185 assert(buffer != GSS_C_NO_BUFFER);
188 buffer->value = NULL;
190 types = GSSEAP_CALLOC(nexts, sizeof(OM_uint32));
192 major = GSS_S_FAILURE;
197 for (i = 0, j = 0; i < nexts; i++) {
198 const struct gss_eap_extension_provider *ext = &exts[i];
199 gss_buffer_desc extension = GSS_C_EMPTY_BUFFER;
201 types[j] = ext->type;
203 types[j] |= EXT_FLAG_CRITICAL;
205 major = ext->make(minor, cred, ctx, chanBindings, &extension);
206 if (GSS_ERROR(major)) {
213 major = gss_add_buffer_set_member(minor, &extension, &extensions);
214 if (GSS_ERROR(major))
220 assert(j == (extensions == GSS_C_NO_BUFFER_SET ? 0 : extensions->count));
222 major = encodeExtensions(minor, extensions, types, buffer);
223 if (GSS_ERROR(major))
227 gss_release_buffer_set(&tmpMinor, &extensions);
235 gssEapMakeExtensions(OM_uint32 *minor,
238 gss_channel_bindings_t chanBindings,
242 const struct gss_eap_extension_provider *exts;
244 if (CTX_IS_INITIATOR(ctx)) {
245 exts = eapGssInitExtensions;
246 nexts = sizeof(eapGssInitExtensions) / sizeof(eapGssInitExtensions[0]);
248 exts = eapGssAcceptExtensions;
249 nexts = sizeof(eapGssAcceptExtensions) / sizeof(eapGssAcceptExtensions[0]);
252 return makeExtensions(minor, cred, ctx, exts, nexts, chanBindings, buffer);
256 verifyExtensions(OM_uint32 *minor,
259 const struct gss_eap_extension_provider *exts,
261 gss_channel_bindings_t chanBindings,
262 const gss_buffer_t buffer)
264 OM_uint32 major, tmpMinor;
265 gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
266 OM_uint32 *types = NULL;
269 major = decodeExtensions(minor, buffer, &extensions, &types);
270 if (GSS_ERROR(major))
273 for (i = 0; i < nexts; i++) {
274 const struct gss_eap_extension_provider *ext = &exts[i];
275 gss_buffer_t extension = GSS_C_NO_BUFFER;
278 for (j = 0; j < extensions->count; j++) {
279 if ((types[j] & EXT_TYPE_MASK) == ext->type) {
280 extension = &extensions->elements[j];
285 if (extension != GSS_C_NO_BUFFER) {
286 /* Process extension and mark as verified */
287 major = ext->verify(minor, cred, ctx, chanBindings,
288 &extensions->elements[j]);
289 if (GSS_ERROR(major))
292 types[j] |= EXT_FLAG_VERIFIED;
293 } else if (ext->required) {
294 /* Required extension missing */
295 major = GSS_S_UNAVAILABLE;
296 *minor = GSSEAP_MISSING_REQUIRED_EXT;
301 /* Check we processed all critical extensions */
302 for (i = 0; i < extensions->count; i++) {
303 if ((types[i] & EXT_FLAG_CRITICAL) &&
304 (types[i] & EXT_FLAG_VERIFIED) == 0) {
305 major = GSS_S_UNAVAILABLE;
306 *minor = GSSEAP_CRIT_EXT_UNAVAILABLE;
311 major = GSS_S_COMPLETE;
315 gss_release_buffer_set(&tmpMinor, &extensions);
323 gssEapVerifyExtensions(OM_uint32 *minor,
326 gss_channel_bindings_t chanBindings,
327 const gss_buffer_t buffer)
330 const struct gss_eap_extension_provider *exts;
332 if (CTX_IS_INITIATOR(ctx)) {
333 exts = eapGssAcceptExtensions;
334 nexts = sizeof(eapGssAcceptExtensions) / sizeof(eapGssAcceptExtensions[0]);
336 exts = eapGssInitExtensions;
337 nexts = sizeof(eapGssInitExtensions) / sizeof(eapGssInitExtensions[0]);
340 return verifyExtensions(minor, cred, ctx, exts, nexts, chanBindings, buffer);
344 encodeExtensions(OM_uint32 *minor,
345 gss_buffer_set_t extensions,
349 OM_uint32 major, tmpMinor;
350 size_t required = 0, i;
353 buffer->value = NULL;
356 if (extensions != GSS_C_NO_BUFFER_SET) {
357 for (i = 0; i < extensions->count; i++) {
358 required += 8 + extensions->elements[i].length;
363 * We must always return a non-NULL token otherwise the calling state
364 * machine assumes we are finished. Hence care in case malloc(0) does
367 buffer->value = GSSEAP_MALLOC(required ? required : 1);
368 if (buffer->value == NULL) {
369 major = GSS_S_FAILURE;
374 buffer->length = required;
375 p = (unsigned char *)buffer->value;
377 if (extensions != GSS_C_NO_BUFFER_SET) {
378 for (i = 0; i < extensions->count; i++) {
379 gss_buffer_t extension = &extensions->elements[i];
381 assert((types[i] & EXT_FLAG_VERIFIED) == 0); /* private flag */
384 * Extensions are encoded as type-length-value, where the upper
385 * bit of the type indicates criticality.
387 store_uint32_be(types[i], &p[0]);
388 store_uint32_be(extension->length, &p[4]);
389 memcpy(&p[8], extension->value, extension->length);
391 p += 8 + extension->length;
395 assert(p == (unsigned char *)buffer->value + required);
396 assert(buffer->value != NULL);
398 major = GSS_S_COMPLETE;
402 if (GSS_ERROR(major)) {
403 gss_release_buffer(&tmpMinor, buffer);
410 decodeExtensions(OM_uint32 *minor,
411 const gss_buffer_t buffer,
412 gss_buffer_set_t *pExtensions,
415 OM_uint32 major, tmpMinor;
416 gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
417 OM_uint32 *types = NULL;
421 *pExtensions = GSS_C_NO_BUFFER_SET;
424 major = gss_create_empty_buffer_set(minor, &extensions);
425 if (GSS_ERROR(major))
428 if (buffer->length == 0) {
429 major = GSS_S_COMPLETE;
433 p = (unsigned char *)buffer->value;
434 remain = buffer->length;
438 gss_buffer_desc extension;
441 major = GSS_S_DEFECTIVE_TOKEN;
442 *minor = GSSEAP_TOK_TRUNC;
446 ntypes = GSSEAP_REALLOC(types,
447 (extensions->count + 1) * sizeof(OM_uint32));
448 if (ntypes == NULL) {
449 major = GSS_S_FAILURE;
455 types[extensions->count] = load_uint32_be(&p[0]);
456 extension.length = load_uint32_be(&p[4]);
458 if (remain < 8 + extension.length) {
459 major = GSS_S_DEFECTIVE_TOKEN;
460 *minor = GSSEAP_TOK_TRUNC;
463 extension.value = &p[8];
465 major = gss_add_buffer_set_member(minor, &extension, &extensions);
466 if (GSS_ERROR(major))
469 p += 8 + extension.length;
470 remain -= 8 + extension.length;
471 } while (remain != 0);
474 if (GSS_ERROR(major)) {
475 gss_release_buffer_set(&tmpMinor, &extensions);
479 *pExtensions = extensions;