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 makeGssChannelBindings(OM_uint32 *minor,
39 gss_channel_bindings_t chanBindings,
40 gss_buffer_t outputToken)
43 gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER;
45 if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS)
46 buffer = chanBindings->application_data;
48 major = gssEapWrap(minor, ctx, TRUE, GSS_C_QOP_DEFAULT,
49 &buffer, NULL, outputToken);
53 return GSS_S_COMPLETE;
57 verifyGssChannelBindings(OM_uint32 *minor,
60 gss_channel_bindings_t chanBindings,
61 gss_buffer_t inputToken)
63 OM_uint32 major, tmpMinor;
64 gss_iov_buffer_desc iov[2];
66 iov[0].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE;
67 iov[0].buffer.length = 0;
68 iov[0].buffer.value = NULL;
70 iov[1].type = GSS_IOV_BUFFER_TYPE_STREAM;
71 iov[1].buffer = *inputToken;
73 major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
74 iov, 2, TOK_TYPE_WRAP);
78 if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS &&
79 !bufferEqual(&iov[0].buffer, &chanBindings->application_data)) {
80 major = GSS_S_BAD_BINDINGS;
82 major = GSS_S_COMPLETE;
85 gss_release_buffer(&tmpMinor, &iov[0].buffer);
90 static struct gss_eap_extension_provider
91 eapGssInitExtensions[] = {
93 EXT_TYPE_GSS_CHANNEL_BINDINGS,
96 makeGssChannelBindings,
97 verifyGssChannelBindings
102 makeReauthCreds(OM_uint32 *minor,
105 gss_channel_bindings_t chanBindings,
106 gss_buffer_t outputToken)
108 OM_uint32 major = GSS_S_UNAVAILABLE;
110 #ifdef GSSEAP_ENABLE_REAUTH
112 * If we're built with fast reauthentication enabled, then
113 * fabricate a ticket from the initiator to ourselves.
115 major = gssEapMakeReauthCreds(minor, ctx, cred, outputToken);
122 verifyReauthCreds(OM_uint32 *minor,
125 gss_channel_bindings_t chanBindings,
126 gss_buffer_t inputToken)
128 #ifdef GSSEAP_ENABLE_REAUTH
129 return gssEapStoreReauthCreds(minor, ctx, cred, inputToken);
131 return GSS_S_UNAVAILABLE;
135 static struct gss_eap_extension_provider
136 eapGssAcceptExtensions[] = {
138 EXT_TYPE_REAUTH_CREDS,
147 encodeExtensions(OM_uint32 *minor,
148 gss_buffer_set_t extensions,
152 OM_uint32 major, tmpMinor;
153 size_t required = 0, i;
156 buffer->value = NULL;
159 if (extensions != GSS_C_NO_BUFFER_SET) {
160 for (i = 0; i < extensions->count; i++) {
161 required += 8 + extensions->elements[i].length;
166 * We must always return a non-NULL token otherwise the calling state
167 * machine assumes we are finished. Hence care in case malloc(0) does
170 buffer->value = GSSEAP_MALLOC(required ? required : 1);
171 if (buffer->value == NULL) {
173 major = GSS_S_FAILURE;
177 buffer->length = required;
178 p = (unsigned char *)buffer->value;
180 if (extensions != GSS_C_NO_BUFFER_SET) {
181 for (i = 0; i < extensions->count; i++) {
182 gss_buffer_t extension = &extensions->elements[i];
184 assert((types[i] & EXT_FLAG_VERIFIED) == 0); /* private flag */
187 * Extensions are encoded as type-length-value, where the upper
188 * bit of the type indicates criticality.
190 store_uint32_be(types[i], &p[0]);
191 store_uint32_be(extension->length, &p[4]);
192 memcpy(&p[8], extension->value, extension->length);
194 p += 8 + extension->length;
198 assert(p == (unsigned char *)buffer->value + required);
199 assert(buffer->value != NULL);
202 if (GSS_ERROR(major)) {
203 gss_release_buffer(&tmpMinor, buffer);
210 decodeExtensions(OM_uint32 *minor,
211 const gss_buffer_t buffer,
212 gss_buffer_set_t *pExtensions,
215 OM_uint32 major, tmpMinor;
216 gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
217 OM_uint32 *types = NULL;
221 *pExtensions = GSS_C_NO_BUFFER_SET;
224 major = gss_create_empty_buffer_set(minor, &extensions);
225 if (GSS_ERROR(major))
228 if (buffer->length == 0) {
229 major = GSS_S_COMPLETE;
233 p = (unsigned char *)buffer->value;
234 remain = buffer->length;
238 gss_buffer_desc extension;
241 major = GSS_S_DEFECTIVE_TOKEN;
245 ntypes = GSSEAP_REALLOC(types,
246 (extensions->count + 1) * sizeof(OM_uint32));
247 if (ntypes == NULL) {
249 major = GSS_S_FAILURE;
254 types[extensions->count] = load_uint32_be(&p[0]);
255 extension.length = load_uint32_be(&p[4]);
257 if (remain < 8 + extension.length) {
258 major = GSS_S_DEFECTIVE_TOKEN;
261 extension.value = &p[8];
263 major = gss_add_buffer_set_member(minor, &extension, &extensions);
264 if (GSS_ERROR(major))
267 p += 8 + extension.length;
268 remain -= 8 + extension.length;
269 } while (remain != 0);
272 if (GSS_ERROR(major)) {
273 gss_release_buffer_set(&tmpMinor, &extensions);
277 *pExtensions = extensions;
285 gssEapMakeExtensions(OM_uint32 *minor,
288 gss_channel_bindings_t chanBindings,
291 OM_uint32 major, tmpMinor;
293 gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
295 const struct gss_eap_extension_provider *exts;
297 if (CTX_IS_INITIATOR(ctx)) {
298 exts = eapGssInitExtensions;
299 nexts = sizeof(eapGssInitExtensions) / sizeof(eapGssInitExtensions[0]);
301 exts = eapGssAcceptExtensions;
302 nexts = sizeof(eapGssAcceptExtensions) / sizeof(eapGssAcceptExtensions[0]);
305 assert(buffer != GSS_C_NO_BUFFER);
308 buffer->value = NULL;
310 types = GSSEAP_CALLOC(nexts, sizeof(OM_uint32));
313 major = GSS_S_FAILURE;
317 for (i = 0, j = 0; i < nexts; i++) {
318 const struct gss_eap_extension_provider *ext = &exts[i];
319 gss_buffer_desc extension = GSS_C_EMPTY_BUFFER;
321 types[j] = ext->type;
323 types[j] |= EXT_FLAG_CRITICAL;
325 major = ext->make(minor, cred, ctx, chanBindings, &extension);
326 if (GSS_ERROR(major)) {
333 major = gss_add_buffer_set_member(minor, &extension, &extensions);
334 if (GSS_ERROR(major))
340 assert(j == (extensions == GSS_C_NO_BUFFER_SET ? 0 : extensions->count));
342 major = encodeExtensions(minor, extensions, types, buffer);
343 if (GSS_ERROR(major))
347 gss_release_buffer_set(&tmpMinor, &extensions);
355 gssEapVerifyExtensions(OM_uint32 *minor,
358 gss_channel_bindings_t chanBindings,
359 const gss_buffer_t buffer)
361 OM_uint32 major, tmpMinor;
362 gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
363 OM_uint32 *types = NULL;
365 const struct gss_eap_extension_provider *exts;
367 if (CTX_IS_INITIATOR(ctx)) {
368 exts = eapGssAcceptExtensions;
369 nexts = sizeof(eapGssAcceptExtensions) / sizeof(eapGssAcceptExtensions[0]);
371 exts = eapGssInitExtensions;
372 nexts = sizeof(eapGssInitExtensions) / sizeof(eapGssInitExtensions[0]);
375 major = decodeExtensions(minor, buffer, &extensions, &types);
376 if (GSS_ERROR(major))
379 for (i = 0; i < nexts; i++) {
380 const struct gss_eap_extension_provider *ext = &exts[i];
381 gss_buffer_t extension = GSS_C_NO_BUFFER;
384 for (j = 0; j < extensions->count; j++) {
385 if ((types[j] & EXT_TYPE_MASK) == ext->type) {
386 extension = &extensions->elements[j];
391 if (extension != GSS_C_NO_BUFFER) {
392 /* Process extension and mark as verified */
393 major = ext->verify(minor, cred, ctx, chanBindings,
394 &extensions->elements[j]);
395 if (GSS_ERROR(major))
398 types[j] |= EXT_FLAG_VERIFIED;
399 } else if (ext->required) {
400 /* Required extension missing */
402 major = GSS_S_UNAVAILABLE;
403 gssEapSaveStatusInfo(*minor,
404 "Missing required GSS EAP extension %08x",
410 /* Check we processed all critical extensions */
411 for (i = 0; i < extensions->count; i++) {
412 if ((types[i] & EXT_FLAG_CRITICAL) &&
413 (types[i] & EXT_FLAG_VERIFIED) == 0) {
415 major = GSS_S_UNAVAILABLE;
416 gssEapSaveStatusInfo(*minor,
417 "Received unknown critical GSS EAP extension %08x",
418 (types[i] & EXT_TYPE_MASK));
424 major = GSS_S_COMPLETE;
427 gss_release_buffer_set(&tmpMinor, &extensions);