Try building with eap from source tree
[mech_eap.orig] / util_exts.c
1 /*
2  * Copyright (c) 2011, JANET(UK)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
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.
15  *
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.
19  *
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
30  * SUCH DAMAGE.
31  */
32
33 /*
34  * Extension token support.
35  */
36
37 #include "gssapiP_eap.h"
38
39 static OM_uint32
40 encodeExtensions(OM_uint32 *minor,
41                  gss_buffer_set_t extensions,
42                  OM_uint32 *types,
43                  gss_buffer_t buffer);
44
45 static OM_uint32
46 decodeExtensions(OM_uint32 *minor,
47                  const gss_buffer_t buffer,
48                  gss_buffer_set_t *pExtensions,
49                  OM_uint32 **pTypes);
50
51 /*
52  * Initiator extensions
53  */
54 static OM_uint32
55 makeGssChannelBindings(OM_uint32 *minor,
56                        gss_cred_id_t cred,
57                        gss_ctx_id_t ctx,
58                        gss_channel_bindings_t chanBindings,
59                        gss_buffer_t outputToken)
60 {
61     OM_uint32 major;
62     gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER;
63
64     if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS)
65         buffer = chanBindings->application_data;
66
67     major = gssEapWrap(minor, ctx, TRUE, GSS_C_QOP_DEFAULT,
68                        &buffer, NULL, outputToken);
69     if (GSS_ERROR(major))
70         return major;
71
72     return GSS_S_COMPLETE;
73 }
74
75 static OM_uint32
76 verifyGssChannelBindings(OM_uint32 *minor,
77                          gss_cred_id_t cred,
78                          gss_ctx_id_t ctx,
79                          gss_channel_bindings_t chanBindings,
80                          gss_buffer_t inputToken)
81 {
82     OM_uint32 major, tmpMinor;
83     gss_iov_buffer_desc iov[2];
84
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;
88
89     iov[1].type = GSS_IOV_BUFFER_TYPE_STREAM;
90     iov[1].buffer = *inputToken;
91
92     major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
93                                     iov, 2, TOK_TYPE_WRAP);
94     if (GSS_ERROR(major))
95         return GSS_S_BAD_BINDINGS;
96
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;
101     } else {
102         major = GSS_S_COMPLETE;
103     }
104
105     gss_release_buffer(&tmpMinor, &iov[0].buffer);
106
107     return major;
108 }
109
110 static struct gss_eap_extension_provider
111 eapGssInitExtensions[] = {
112     {
113         EXT_TYPE_GSS_CHANNEL_BINDINGS,
114         1, /* critical */
115         1, /* required */
116         makeGssChannelBindings,
117         verifyGssChannelBindings
118     },
119 };
120
121 /*
122  * Acceptor extensions
123  */
124 static OM_uint32
125 makeReauthCreds(OM_uint32 *minor,
126                 gss_cred_id_t cred,
127                 gss_ctx_id_t ctx,
128                 gss_channel_bindings_t chanBindings,
129                 gss_buffer_t outputToken)
130 {
131     OM_uint32 major = GSS_S_UNAVAILABLE;
132
133 #ifdef GSSEAP_ENABLE_REAUTH
134     /*
135      * If we're built with fast reauthentication enabled, then
136      * fabricate a ticket from the initiator to ourselves.
137      */
138     major = gssEapMakeReauthCreds(minor, ctx, cred, outputToken);
139 #endif
140
141     return major;
142 }
143
144 static OM_uint32
145 verifyReauthCreds(OM_uint32 *minor,
146                   gss_cred_id_t cred,
147                   gss_ctx_id_t ctx,
148                   gss_channel_bindings_t chanBindings,
149                   gss_buffer_t inputToken)
150 {
151     OM_uint32 major = GSS_S_UNAVAILABLE;
152
153 #ifdef GSSEAP_ENABLE_REAUTH
154     major = gssEapStoreReauthCreds(minor, ctx, cred, inputToken);
155 #endif
156
157     return major;
158 }
159
160 static struct gss_eap_extension_provider
161 eapGssAcceptExtensions[] = {
162     {
163         EXT_TYPE_REAUTH_CREDS,
164         0, /* critical */
165         0, /* required */
166         makeReauthCreds,
167         verifyReauthCreds
168     },
169 };
170
171 OM_uint32
172 makeExtensions(OM_uint32 *minor,
173                gss_cred_id_t cred,
174                gss_ctx_id_t ctx,
175                const struct gss_eap_extension_provider *exts,
176                size_t nexts,
177                gss_channel_bindings_t chanBindings,
178                gss_buffer_t buffer)
179 {
180     OM_uint32 major, tmpMinor;
181     size_t i, j;
182     gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
183     OM_uint32 *types;
184
185     assert(buffer != GSS_C_NO_BUFFER);
186
187     buffer->length = 0;
188     buffer->value = NULL;
189
190     types = GSSEAP_CALLOC(nexts, sizeof(OM_uint32));
191     if (types == NULL) {
192         major = GSS_S_FAILURE;
193         *minor = ENOMEM;
194         goto cleanup;
195     }
196
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;
200
201         types[j] = ext->type;
202         if (ext->critical)
203             types[j] |= EXT_FLAG_CRITICAL;
204
205         major = ext->make(minor, cred, ctx, chanBindings, &extension);
206         if (GSS_ERROR(major)) {
207             if (ext->critical)
208                 goto cleanup;
209             else
210                 continue;
211         }
212
213         major = gss_add_buffer_set_member(minor, &extension, &extensions);
214         if (GSS_ERROR(major))
215             goto cleanup;
216
217         j++;
218     }
219
220     assert(j == (extensions == GSS_C_NO_BUFFER_SET ? 0 : extensions->count));
221
222     major = encodeExtensions(minor, extensions, types, buffer);
223     if (GSS_ERROR(major))
224         goto cleanup;
225
226 cleanup:
227     gss_release_buffer_set(&tmpMinor, &extensions);
228     if (types != NULL)
229         GSSEAP_FREE(types);
230
231     return major;
232 }
233
234 OM_uint32
235 gssEapMakeExtensions(OM_uint32 *minor,
236                      gss_cred_id_t cred,
237                      gss_ctx_id_t ctx,
238                      gss_channel_bindings_t chanBindings,
239                      gss_buffer_t buffer)
240 {
241     size_t nexts;
242     const struct gss_eap_extension_provider *exts;
243
244     if (CTX_IS_INITIATOR(ctx)) {
245         exts = eapGssInitExtensions;
246         nexts = sizeof(eapGssInitExtensions) / sizeof(eapGssInitExtensions[0]);
247     } else {
248         exts = eapGssAcceptExtensions;
249         nexts = sizeof(eapGssAcceptExtensions) / sizeof(eapGssAcceptExtensions[0]);
250     }
251
252     return makeExtensions(minor, cred, ctx, exts, nexts, chanBindings, buffer);
253 }
254
255 static OM_uint32
256 verifyExtensions(OM_uint32 *minor,
257                  gss_cred_id_t cred,
258                  gss_ctx_id_t ctx,
259                  const struct gss_eap_extension_provider *exts,
260                  size_t nexts,
261                  gss_channel_bindings_t chanBindings,
262                  const gss_buffer_t buffer)
263 {
264     OM_uint32 major, tmpMinor;
265     gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
266     OM_uint32 *types = NULL;
267     size_t i;
268
269     major = decodeExtensions(minor, buffer, &extensions, &types);
270     if (GSS_ERROR(major))
271         goto cleanup;
272
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;
276         size_t j;
277
278         for (j = 0; j < extensions->count; j++) {
279             if ((types[j] & EXT_TYPE_MASK) == ext->type) {
280                 extension = &extensions->elements[j];
281                 break;
282             }
283         }
284
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))
290                 goto cleanup;
291
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;
297             goto cleanup;
298         }
299     }
300
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;
307             goto cleanup;
308         }
309     }
310
311     major = GSS_S_COMPLETE;
312     *minor = 0;
313
314 cleanup:
315     gss_release_buffer_set(&tmpMinor, &extensions);
316     if (types != NULL)
317         GSSEAP_FREE(types);
318
319     return major;
320 }
321
322 OM_uint32
323 gssEapVerifyExtensions(OM_uint32 *minor,
324                        gss_cred_id_t cred,
325                        gss_ctx_id_t ctx,
326                        gss_channel_bindings_t chanBindings,
327                        const gss_buffer_t buffer)
328 {
329     size_t nexts;
330     const struct gss_eap_extension_provider *exts;
331
332     if (CTX_IS_INITIATOR(ctx)) {
333         exts = eapGssAcceptExtensions;
334         nexts = sizeof(eapGssAcceptExtensions) / sizeof(eapGssAcceptExtensions[0]);
335     } else {
336         exts = eapGssInitExtensions;
337         nexts = sizeof(eapGssInitExtensions) / sizeof(eapGssInitExtensions[0]);
338     }
339
340     return verifyExtensions(minor, cred, ctx, exts, nexts, chanBindings, buffer);
341 }
342
343 static OM_uint32
344 encodeExtensions(OM_uint32 *minor,
345                  gss_buffer_set_t extensions,
346                  OM_uint32 *types,
347                  gss_buffer_t buffer)
348 {
349     OM_uint32 major, tmpMinor;
350     size_t required = 0, i;
351     unsigned char *p;
352
353     buffer->value = NULL;
354     buffer->length = 0;
355
356     if (extensions != GSS_C_NO_BUFFER_SET) {
357         for (i = 0; i < extensions->count; i++) {
358             required += 8 + extensions->elements[i].length;
359         }
360     }
361
362     /*
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
365      * return NULL.
366      */
367     buffer->value = GSSEAP_MALLOC(required ? required : 1);
368     if (buffer->value == NULL) {
369         major = GSS_S_FAILURE;
370         *minor = ENOMEM;
371         goto cleanup;
372     }
373
374     buffer->length = required;
375     p = (unsigned char *)buffer->value;
376
377     if (extensions != GSS_C_NO_BUFFER_SET) {
378         for (i = 0; i < extensions->count; i++) {
379             gss_buffer_t extension = &extensions->elements[i];
380
381             assert((types[i] & EXT_FLAG_VERIFIED) == 0); /* private flag */
382
383              /*
384               * Extensions are encoded as type-length-value, where the upper
385               * bit of the type indicates criticality.
386               */
387             store_uint32_be(types[i], &p[0]);
388             store_uint32_be(extension->length, &p[4]);
389             memcpy(&p[8], extension->value, extension->length);
390
391             p += 8 + extension->length;
392         }
393     }
394
395     assert(p == (unsigned char *)buffer->value + required);
396     assert(buffer->value != NULL);
397
398     major = GSS_S_COMPLETE;
399     *minor = 0;
400
401 cleanup:
402     if (GSS_ERROR(major)) {
403         gss_release_buffer(&tmpMinor, buffer);
404     }
405
406     return major;
407 }
408
409 static OM_uint32
410 decodeExtensions(OM_uint32 *minor,
411                  const gss_buffer_t buffer,
412                  gss_buffer_set_t *pExtensions,
413                  OM_uint32 **pTypes)
414 {
415     OM_uint32 major, tmpMinor;
416     gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
417     OM_uint32 *types = NULL;
418     unsigned char *p;
419     size_t remain;
420
421     *pExtensions = GSS_C_NO_BUFFER_SET;
422     *pTypes = NULL;
423
424     major = gss_create_empty_buffer_set(minor, &extensions);
425     if (GSS_ERROR(major))
426         goto cleanup;
427
428     if (buffer->length == 0) {
429         major = GSS_S_COMPLETE;
430         goto cleanup;
431     }
432
433     p = (unsigned char *)buffer->value;
434     remain = buffer->length;
435
436     do {
437         OM_uint32 *ntypes;
438         gss_buffer_desc extension;
439
440         if (remain < 8) {
441             major = GSS_S_DEFECTIVE_TOKEN;
442             *minor = GSSEAP_TOK_TRUNC;
443             goto cleanup;
444         }
445
446         ntypes = GSSEAP_REALLOC(types,
447                                 (extensions->count + 1) * sizeof(OM_uint32));
448         if (ntypes == NULL) {
449             major = GSS_S_FAILURE;
450             *minor = ENOMEM;
451             goto cleanup;
452         }
453         types = ntypes;
454
455         types[extensions->count] = load_uint32_be(&p[0]);
456         extension.length = load_uint32_be(&p[4]);
457
458         if (remain < 8 + extension.length) {
459             major = GSS_S_DEFECTIVE_TOKEN;
460             *minor = GSSEAP_TOK_TRUNC;
461             goto cleanup;
462         }
463         extension.value = &p[8];
464
465         major = gss_add_buffer_set_member(minor, &extension, &extensions);
466         if (GSS_ERROR(major))
467             goto cleanup;
468
469         p      += 8 + extension.length;
470         remain -= 8 + extension.length;
471     } while (remain != 0);
472
473 cleanup:
474     if (GSS_ERROR(major)) {
475         gss_release_buffer_set(&tmpMinor, &extensions);
476         if (types != NULL)
477             GSSEAP_FREE(types);
478     } else {
479         *pExtensions = extensions;
480         *pTypes = types;
481     }
482
483     return major;
484 }