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 #ifdef GSSEAP_ENABLE_REAUTH
147 return gssEapStoreReauthCreds(minor, ctx, cred, inputToken);
149 return GSS_S_UNAVAILABLE;
153 static struct gss_eap_extension_provider
154 eapGssAcceptExtensions[] = {
156 EXT_TYPE_REAUTH_CREDS,
165 gssEapMakeExtensions(OM_uint32 *minor,
168 gss_channel_bindings_t chanBindings,
171 OM_uint32 major, tmpMinor;
173 gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
175 const struct gss_eap_extension_provider *exts;
177 if (CTX_IS_INITIATOR(ctx)) {
178 exts = eapGssInitExtensions;
179 nexts = sizeof(eapGssInitExtensions) / sizeof(eapGssInitExtensions[0]);
181 exts = eapGssAcceptExtensions;
182 nexts = sizeof(eapGssAcceptExtensions) / sizeof(eapGssAcceptExtensions[0]);
185 assert(buffer != GSS_C_NO_BUFFER);
188 buffer->value = NULL;
190 types = GSSEAP_CALLOC(nexts, sizeof(OM_uint32));
193 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 gssEapVerifyExtensions(OM_uint32 *minor,
238 gss_channel_bindings_t chanBindings,
239 const gss_buffer_t buffer)
241 OM_uint32 major, tmpMinor;
242 gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
243 OM_uint32 *types = NULL;
245 const struct gss_eap_extension_provider *exts;
247 if (CTX_IS_INITIATOR(ctx)) {
248 exts = eapGssAcceptExtensions;
249 nexts = sizeof(eapGssAcceptExtensions) / sizeof(eapGssAcceptExtensions[0]);
251 exts = eapGssInitExtensions;
252 nexts = sizeof(eapGssInitExtensions) / sizeof(eapGssInitExtensions[0]);
255 major = decodeExtensions(minor, buffer, &extensions, &types);
256 if (GSS_ERROR(major))
259 for (i = 0; i < nexts; i++) {
260 const struct gss_eap_extension_provider *ext = &exts[i];
261 gss_buffer_t extension = GSS_C_NO_BUFFER;
264 for (j = 0; j < extensions->count; j++) {
265 if ((types[j] & EXT_TYPE_MASK) == ext->type) {
266 extension = &extensions->elements[j];
271 if (extension != GSS_C_NO_BUFFER) {
272 /* Process extension and mark as verified */
273 major = ext->verify(minor, cred, ctx, chanBindings,
274 &extensions->elements[j]);
275 if (GSS_ERROR(major))
278 types[j] |= EXT_FLAG_VERIFIED;
279 } else if (ext->required) {
280 /* Required extension missing */
282 major = GSS_S_UNAVAILABLE;
283 gssEapSaveStatusInfo(*minor,
284 "Missing required GSS EAP extension %08x",
290 /* Check we processed all critical extensions */
291 for (i = 0; i < extensions->count; i++) {
292 if ((types[i] & EXT_FLAG_CRITICAL) &&
293 (types[i] & EXT_FLAG_VERIFIED) == 0) {
295 major = GSS_S_UNAVAILABLE;
296 gssEapSaveStatusInfo(*minor,
297 "Received unknown critical GSS EAP extension %08x",
298 (types[i] & EXT_TYPE_MASK));
304 major = GSS_S_COMPLETE;
307 gss_release_buffer_set(&tmpMinor, &extensions);
315 encodeExtensions(OM_uint32 *minor,
316 gss_buffer_set_t extensions,
320 OM_uint32 major, tmpMinor;
321 size_t required = 0, i;
324 buffer->value = NULL;
327 if (extensions != GSS_C_NO_BUFFER_SET) {
328 for (i = 0; i < extensions->count; i++) {
329 required += 8 + extensions->elements[i].length;
334 * We must always return a non-NULL token otherwise the calling state
335 * machine assumes we are finished. Hence care in case malloc(0) does
338 buffer->value = GSSEAP_MALLOC(required ? required : 1);
339 if (buffer->value == NULL) {
341 major = GSS_S_FAILURE;
345 buffer->length = required;
346 p = (unsigned char *)buffer->value;
348 if (extensions != GSS_C_NO_BUFFER_SET) {
349 for (i = 0; i < extensions->count; i++) {
350 gss_buffer_t extension = &extensions->elements[i];
352 assert((types[i] & EXT_FLAG_VERIFIED) == 0); /* private flag */
355 * Extensions are encoded as type-length-value, where the upper
356 * bit of the type indicates criticality.
358 store_uint32_be(types[i], &p[0]);
359 store_uint32_be(extension->length, &p[4]);
360 memcpy(&p[8], extension->value, extension->length);
362 p += 8 + extension->length;
366 assert(p == (unsigned char *)buffer->value + required);
367 assert(buffer->value != NULL);
370 if (GSS_ERROR(major)) {
371 gss_release_buffer(&tmpMinor, buffer);
378 decodeExtensions(OM_uint32 *minor,
379 const gss_buffer_t buffer,
380 gss_buffer_set_t *pExtensions,
383 OM_uint32 major, tmpMinor;
384 gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
385 OM_uint32 *types = NULL;
389 *pExtensions = GSS_C_NO_BUFFER_SET;
392 major = gss_create_empty_buffer_set(minor, &extensions);
393 if (GSS_ERROR(major))
396 if (buffer->length == 0) {
397 major = GSS_S_COMPLETE;
401 p = (unsigned char *)buffer->value;
402 remain = buffer->length;
406 gss_buffer_desc extension;
409 major = GSS_S_DEFECTIVE_TOKEN;
413 ntypes = GSSEAP_REALLOC(types,
414 (extensions->count + 1) * sizeof(OM_uint32));
415 if (ntypes == NULL) {
417 major = GSS_S_FAILURE;
422 types[extensions->count] = load_uint32_be(&p[0]);
423 extension.length = load_uint32_be(&p[4]);
425 if (remain < 8 + extension.length) {
426 major = GSS_S_DEFECTIVE_TOKEN;
429 extension.value = &p[8];
431 major = gss_add_buffer_set_member(minor, &extension, &extensions);
432 if (GSS_ERROR(major))
435 p += 8 + extension.length;
436 remain -= 8 + extension.length;
437 } while (remain != 0);
440 if (GSS_ERROR(major)) {
441 gss_release_buffer_set(&tmpMinor, &extensions);
445 *pExtensions = extensions;