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);
91 return GSS_S_BAD_BINDINGS;
93 if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS &&
94 !bufferEqual(&iov[0].buffer, &chanBindings->application_data)) {
95 *minor = GSSEAP_BINDINGS_MISMATCH;
96 major = GSS_S_BAD_BINDINGS;
98 major = GSS_S_COMPLETE;
101 gss_release_buffer(&tmpMinor, &iov[0].buffer);
106 static struct gss_eap_extension_provider
107 eapGssInitExtensions[] = {
109 EXT_TYPE_GSS_CHANNEL_BINDINGS,
112 makeGssChannelBindings,
113 verifyGssChannelBindings
118 * Acceptor extensions
121 makeReauthCreds(OM_uint32 *minor,
124 gss_channel_bindings_t chanBindings,
125 gss_buffer_t outputToken)
127 OM_uint32 major = GSS_S_UNAVAILABLE;
129 #ifdef GSSEAP_ENABLE_REAUTH
131 * If we're built with fast reauthentication enabled, then
132 * fabricate a ticket from the initiator to ourselves.
134 major = gssEapMakeReauthCreds(minor, ctx, cred, outputToken);
141 verifyReauthCreds(OM_uint32 *minor,
144 gss_channel_bindings_t chanBindings,
145 gss_buffer_t inputToken)
147 OM_uint32 major = GSS_S_UNAVAILABLE;
149 #ifdef GSSEAP_ENABLE_REAUTH
150 major = gssEapStoreReauthCreds(minor, ctx, cred, inputToken);
156 static struct gss_eap_extension_provider
157 eapGssAcceptExtensions[] = {
159 EXT_TYPE_REAUTH_CREDS,
168 makeExtensions(OM_uint32 *minor,
171 const struct gss_eap_extension_provider *exts,
173 gss_channel_bindings_t chanBindings,
176 OM_uint32 major, tmpMinor;
178 gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
181 assert(buffer != GSS_C_NO_BUFFER);
184 buffer->value = NULL;
186 types = GSSEAP_CALLOC(nexts, sizeof(OM_uint32));
189 major = GSS_S_FAILURE;
193 for (i = 0, j = 0; i < nexts; i++) {
194 const struct gss_eap_extension_provider *ext = &exts[i];
195 gss_buffer_desc extension = GSS_C_EMPTY_BUFFER;
197 types[j] = ext->type;
199 types[j] |= EXT_FLAG_CRITICAL;
201 major = ext->make(minor, cred, ctx, chanBindings, &extension);
202 if (GSS_ERROR(major)) {
209 major = gss_add_buffer_set_member(minor, &extension, &extensions);
210 if (GSS_ERROR(major))
216 assert(j == (extensions == GSS_C_NO_BUFFER_SET ? 0 : extensions->count));
218 major = encodeExtensions(minor, extensions, types, buffer);
219 if (GSS_ERROR(major))
223 gss_release_buffer_set(&tmpMinor, &extensions);
231 gssEapMakeExtensions(OM_uint32 *minor,
234 gss_channel_bindings_t chanBindings,
238 const struct gss_eap_extension_provider *exts;
240 if (CTX_IS_INITIATOR(ctx)) {
241 exts = eapGssInitExtensions;
242 nexts = sizeof(eapGssInitExtensions) / sizeof(eapGssInitExtensions[0]);
244 exts = eapGssAcceptExtensions;
245 nexts = sizeof(eapGssAcceptExtensions) / sizeof(eapGssAcceptExtensions[0]);
248 return makeExtensions(minor, cred, ctx, exts, nexts, chanBindings, buffer);
252 verifyExtensions(OM_uint32 *minor,
255 const struct gss_eap_extension_provider *exts,
257 gss_channel_bindings_t chanBindings,
258 const gss_buffer_t buffer)
260 OM_uint32 major, tmpMinor;
261 gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
262 OM_uint32 *types = NULL;
265 major = decodeExtensions(minor, buffer, &extensions, &types);
266 if (GSS_ERROR(major))
269 for (i = 0; i < nexts; i++) {
270 const struct gss_eap_extension_provider *ext = &exts[i];
271 gss_buffer_t extension = GSS_C_NO_BUFFER;
274 for (j = 0; j < extensions->count; j++) {
275 if ((types[j] & EXT_TYPE_MASK) == ext->type) {
276 extension = &extensions->elements[j];
281 if (extension != GSS_C_NO_BUFFER) {
282 /* Process extension and mark as verified */
283 major = ext->verify(minor, cred, ctx, chanBindings,
284 &extensions->elements[j]);
285 if (GSS_ERROR(major))
288 types[j] |= EXT_FLAG_VERIFIED;
289 } else if (ext->required) {
290 /* Required extension missing */
291 *minor = GSSEAP_MISSING_REQUIRED_EXT;
292 major = GSS_S_UNAVAILABLE;
297 /* Check we processed all critical extensions */
298 for (i = 0; i < extensions->count; i++) {
299 if ((types[i] & EXT_FLAG_CRITICAL) &&
300 (types[i] & EXT_FLAG_VERIFIED) == 0) {
301 *minor = GSSEAP_CRIT_EXT_UNAVAILABLE;
302 major = GSS_S_UNAVAILABLE;
308 major = GSS_S_COMPLETE;
311 gss_release_buffer_set(&tmpMinor, &extensions);
319 gssEapVerifyExtensions(OM_uint32 *minor,
322 gss_channel_bindings_t chanBindings,
323 const gss_buffer_t buffer)
326 const struct gss_eap_extension_provider *exts;
328 if (CTX_IS_INITIATOR(ctx)) {
329 exts = eapGssAcceptExtensions;
330 nexts = sizeof(eapGssAcceptExtensions) / sizeof(eapGssAcceptExtensions[0]);
332 exts = eapGssInitExtensions;
333 nexts = sizeof(eapGssInitExtensions) / sizeof(eapGssInitExtensions[0]);
336 return verifyExtensions(minor, cred, ctx, exts, nexts, chanBindings, buffer);
340 encodeExtensions(OM_uint32 *minor,
341 gss_buffer_set_t extensions,
345 OM_uint32 major, tmpMinor;
346 size_t required = 0, i;
349 buffer->value = NULL;
352 if (extensions != GSS_C_NO_BUFFER_SET) {
353 for (i = 0; i < extensions->count; i++) {
354 required += 8 + extensions->elements[i].length;
359 * We must always return a non-NULL token otherwise the calling state
360 * machine assumes we are finished. Hence care in case malloc(0) does
363 buffer->value = GSSEAP_MALLOC(required ? required : 1);
364 if (buffer->value == NULL) {
366 major = GSS_S_FAILURE;
370 buffer->length = required;
371 p = (unsigned char *)buffer->value;
373 if (extensions != GSS_C_NO_BUFFER_SET) {
374 for (i = 0; i < extensions->count; i++) {
375 gss_buffer_t extension = &extensions->elements[i];
377 assert((types[i] & EXT_FLAG_VERIFIED) == 0); /* private flag */
380 * Extensions are encoded as type-length-value, where the upper
381 * bit of the type indicates criticality.
383 store_uint32_be(types[i], &p[0]);
384 store_uint32_be(extension->length, &p[4]);
385 memcpy(&p[8], extension->value, extension->length);
387 p += 8 + extension->length;
391 assert(p == (unsigned char *)buffer->value + required);
392 assert(buffer->value != NULL);
395 if (GSS_ERROR(major)) {
396 gss_release_buffer(&tmpMinor, buffer);
403 decodeExtensions(OM_uint32 *minor,
404 const gss_buffer_t buffer,
405 gss_buffer_set_t *pExtensions,
408 OM_uint32 major, tmpMinor;
409 gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
410 OM_uint32 *types = NULL;
414 *pExtensions = GSS_C_NO_BUFFER_SET;
417 major = gss_create_empty_buffer_set(minor, &extensions);
418 if (GSS_ERROR(major))
421 if (buffer->length == 0) {
422 major = GSS_S_COMPLETE;
426 p = (unsigned char *)buffer->value;
427 remain = buffer->length;
431 gss_buffer_desc extension;
434 *minor = GSSEAP_TOK_TRUNC;
435 major = GSS_S_DEFECTIVE_TOKEN;
439 ntypes = GSSEAP_REALLOC(types,
440 (extensions->count + 1) * sizeof(OM_uint32));
441 if (ntypes == NULL) {
443 major = GSS_S_FAILURE;
448 types[extensions->count] = load_uint32_be(&p[0]);
449 extension.length = load_uint32_be(&p[4]);
451 if (remain < 8 + extension.length) {
452 *minor = GSSEAP_TOK_TRUNC;
453 major = GSS_S_DEFECTIVE_TOKEN;
456 extension.value = &p[8];
458 major = gss_add_buffer_set_member(minor, &extension, &extensions);
459 if (GSS_ERROR(major))
462 p += 8 + extension.length;
463 remain -= 8 + extension.length;
464 } while (remain != 0);
467 if (GSS_ERROR(major)) {
468 gss_release_buffer_set(&tmpMinor, &extensions);
472 *pExtensions = extensions;