Merge remote branch 'origin/master' into HEAD
[moonshot.git] / moonshot / mech_eap / util_token.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  * Portions Copyright 1993 by OpenVision Technologies, Inc.
34  *
35  * Permission to use, copy, modify, distribute, and sell this software
36  * and its documentation for any purpose is hereby granted without fee,
37  * provided that the above copyright notice appears in all copies and
38  * that both that copyright notice and this permission notice appear in
39  * supporting documentation, and that the name of OpenVision not be used
40  * in advertising or publicity pertaining to distribution of the software
41  * without specific, written prior permission. OpenVision makes no
42  * representations about the suitability of this software for any
43  * purpose.  It is provided "as is" without express or implied warranty.
44  *
45  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
46  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
47  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
48  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
49  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
50  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
51  * PERFORMANCE OF THIS SOFTWARE.
52  */
53
54 /*
55  * Utility routines for GSS tokens.
56  */
57
58 #include "gssapiP_eap.h"
59
60 OM_uint32
61 gssEapDecodeInnerTokens(OM_uint32 *minor,
62                         const gss_buffer_t buffer,
63                         gss_buffer_set_t *pExtensions,
64                         OM_uint32 **pTypes)
65 {
66     OM_uint32 major, tmpMinor;
67     gss_buffer_set_t extensions = GSS_C_NO_BUFFER_SET;
68     OM_uint32 *types = NULL;
69     unsigned char *p;
70     size_t remain;
71
72     *pExtensions = GSS_C_NO_BUFFER_SET;
73     *pTypes = NULL;
74
75     major = gss_create_empty_buffer_set(minor, &extensions);
76     if (GSS_ERROR(major))
77         goto cleanup;
78
79     if (buffer->length == 0) {
80         major = GSS_S_COMPLETE;
81         goto cleanup;
82     }
83
84     p = (unsigned char *)buffer->value;
85     remain = buffer->length;
86
87     do {
88         OM_uint32 *ntypes;
89         gss_buffer_desc extension;
90
91         if (remain < 8) {
92             major = GSS_S_DEFECTIVE_TOKEN;
93             *minor = GSSEAP_TOK_TRUNC;
94             goto cleanup;
95         }
96
97         ntypes = GSSEAP_REALLOC(types,
98                                 (extensions->count + 1) * sizeof(OM_uint32));
99         if (ntypes == NULL) {
100             major = GSS_S_FAILURE;
101             *minor = ENOMEM;
102             goto cleanup;
103         }
104         types = ntypes;
105
106         types[extensions->count] = load_uint32_be(&p[0]);
107         extension.length = load_uint32_be(&p[4]);
108
109         if (remain < ITOK_HEADER_LENGTH + extension.length) {
110             major = GSS_S_DEFECTIVE_TOKEN;
111             *minor = GSSEAP_TOK_TRUNC;
112             goto cleanup;
113         }
114         extension.value = &p[8];
115
116         major = gss_add_buffer_set_member(minor, &extension, &extensions);
117         if (GSS_ERROR(major))
118             goto cleanup;
119
120         p      += ITOK_HEADER_LENGTH + extension.length;
121         remain -= ITOK_HEADER_LENGTH + extension.length;
122     } while (remain != 0);
123
124 cleanup:
125     if (GSS_ERROR(major)) {
126         gss_release_buffer_set(&tmpMinor, &extensions);
127         if (types != NULL)
128             GSSEAP_FREE(types);
129     } else {
130         *pExtensions = extensions;
131         *pTypes = types;
132     }
133
134     return major;
135 }
136
137 /*
138  * Add some data to the initiator/acceptor conversation.
139  */
140 static OM_uint32
141 recordTokens(OM_uint32 *minor,
142              gss_ctx_id_t ctx,
143              gss_buffer_t tokens,
144              size_t tokensCount)
145 {
146     unsigned char *buf;
147     size_t i, size, offset;
148
149     size = ctx->conversation.length;
150
151     for (i = 0; i < tokensCount; i++)
152         size += tokens[i].length;
153
154     buf = GSSEAP_REALLOC(ctx->conversation.value, size);
155     if (buf == NULL) {
156         *minor = ENOMEM;
157         return GSS_S_FAILURE;
158     }
159
160     offset = ctx->conversation.length;
161
162     ctx->conversation.length = size;
163     ctx->conversation.value = buf;
164
165     for (i = 0; i < tokensCount; i++) {
166         memcpy(buf + offset, tokens[i].value, tokens[i].length);
167         offset += tokens[i].length;
168     }
169
170     *minor = 0;
171     return GSS_S_COMPLETE;
172 }
173
174 /*
175  * Record the context token header.
176  */
177 OM_uint32
178 gssEapRecordContextTokenHeader(OM_uint32 *minor,
179                                gss_ctx_id_t ctx,
180                                enum gss_eap_token_type tokType)
181 {
182     unsigned char wireOidHeader[2], wireTokType[2];
183     gss_buffer_desc buffers[3];
184
185     assert(ctx->mechanismUsed != GSS_C_NO_OID);
186
187     wireOidHeader[0] = 0x06;
188     wireOidHeader[1] = ctx->mechanismUsed->length;
189     buffers[0].length = sizeof(wireOidHeader);
190     buffers[0].value  = wireOidHeader;
191
192     buffers[1].length = ctx->mechanismUsed->length;
193     buffers[1].value  = ctx->mechanismUsed->elements;
194
195     store_uint16_be(tokType, wireTokType);
196     buffers[2].length = sizeof(wireTokType);
197     buffers[2].value = wireTokType;
198
199     return recordTokens(minor, ctx, buffers, sizeof(buffers)/sizeof(buffers[0]));
200 }
201
202 /*
203  * Record an inner context token.
204  */
205 OM_uint32
206 gssEapRecordInnerContextToken(OM_uint32 *minor,
207                               gss_ctx_id_t ctx,
208                               gss_buffer_t innerToken,
209                               OM_uint32 itokType)
210 {
211     gss_buffer_desc buffers[2];
212     unsigned char itokHeader[ITOK_HEADER_LENGTH];
213
214     assert(innerToken != GSS_C_NO_BUFFER);
215
216     store_uint32_be(itokType,           &itokHeader[0]);
217     store_uint32_be(innerToken->length, &itokHeader[4]);
218     buffers[0].length = sizeof(itokHeader);
219     buffers[0].value  = itokHeader;
220
221     buffers[1] = *innerToken;
222
223     return recordTokens(minor, ctx, buffers, sizeof(buffers)/sizeof(buffers[0]));
224 }
225
226 OM_uint32
227 gssEapVerifyContextToken(OM_uint32 *minor,
228                          gss_ctx_id_t ctx,
229                          const gss_buffer_t inputToken,
230                          enum gss_eap_token_type tokType,
231                          gss_buffer_t innerInputToken)
232 {
233     OM_uint32 major;
234     size_t bodySize;
235     unsigned char *p = (unsigned char *)inputToken->value;
236     gss_OID_desc oidBuf;
237     gss_OID oid;
238     enum gss_eap_token_type actualTokType;
239     gss_buffer_desc tokenBuf;
240
241     if (ctx->mechanismUsed != GSS_C_NO_OID) {
242         oid = ctx->mechanismUsed;
243     } else {
244         oidBuf.elements = NULL;
245         oidBuf.length = 0;
246         oid = &oidBuf;
247     }
248
249     major = verifyTokenHeader(minor, oid, &bodySize, &p,
250                               inputToken->length, &actualTokType);
251     if (GSS_ERROR(major))
252         return major;
253
254     if (actualTokType != tokType) {
255         *minor = GSSEAP_WRONG_TOK_ID;
256         return GSS_S_DEFECTIVE_TOKEN;
257     }
258
259     if (ctx->mechanismUsed == GSS_C_NO_OID) {
260         major = gssEapCanonicalizeOid(minor, oid, 0, &ctx->mechanismUsed);
261         if (GSS_ERROR(major))
262             return major;
263     }
264
265     innerInputToken->length = bodySize;
266     innerInputToken->value = p;
267
268     /*
269      * Add OID, tokenType, body to conversation; variable length
270      * header omitted. A better API to verifyTokenHeader would
271      * avoid this ugly pointer arithmetic. XXX FIXME
272      */
273     tokenBuf.value = p - (2 + oid->length + 2);
274     tokenBuf.length = 2 + oid->length + 2 + bodySize;
275
276     major = recordTokens(minor, ctx, &tokenBuf, 1);
277     if (GSS_ERROR(major))
278         return major;
279
280     *minor = 0;
281     return GSS_S_COMPLETE;
282 }
283
284 OM_uint32
285 gssEapEncodeSupportedExts(OM_uint32 *minor,
286                           OM_uint32 *types,
287                           size_t typesCount,
288                           gss_buffer_t outputToken)
289 {
290     size_t i;
291     unsigned char *p;
292
293     outputToken->value = GSSEAP_MALLOC(4 * typesCount);
294     if (outputToken->value == NULL) {
295         *minor = ENOMEM;
296         return GSS_S_FAILURE;
297     }
298     p = (unsigned char *)outputToken->value;
299
300     outputToken->length = 4 * typesCount;
301
302     for (i = 0; i < typesCount; i++) {
303         store_uint32_be(types[i], p);
304         p += 4;
305     }
306
307     *minor = 0;
308     return GSS_S_COMPLETE;
309 }
310
311 OM_uint32
312 gssEapProcessSupportedExts(OM_uint32 *minor,
313                            gss_buffer_t inputToken,
314                            struct gss_eap_itok_map *map,
315                            size_t mapCount,
316                            OM_uint32 *flags)
317 {
318     size_t i;
319     unsigned char *p;
320
321     if ((inputToken->length % 4) != 0) {
322         *minor = GSSEAP_TOK_TRUNC;
323         return GSS_S_DEFECTIVE_TOKEN;
324     }
325
326     p = (unsigned char *)inputToken->value;
327
328     for (i = 0; i < inputToken->length / 4; i++) {
329         OM_uint32 type = load_uint32_be(p);
330         size_t j;
331
332         for (j = 0; j < mapCount; j++) {
333             if (map->type == type) {
334                 *flags |= map->flag;
335                 break;
336             }
337         }
338
339         p += 4;
340     }
341
342     *minor = 0;
343     return GSS_S_COMPLETE;
344 }
345
346 /*
347  * $Id: util_token.c 23457 2009-12-08 00:04:48Z tlyu $
348  */
349
350 /* XXXX this code currently makes the assumption that a mech oid will
351    never be longer than 127 bytes.  This assumption is not inherent in
352    the interfaces, so the code can be fixed if the OSI namespace
353    balloons unexpectedly. */
354
355 /*
356  * Each token looks like this:
357  * 0x60                 tag for APPLICATION 0, SEQUENCE
358  *                              (constructed, definite-length)
359  * <length>             possible multiple bytes, need to parse/generate
360  * 0x06                 tag for OBJECT IDENTIFIER
361  * <moid_length>        compile-time constant string (assume 1 byte)
362  * <moid_bytes>         compile-time constant string
363  * <inner_bytes>        the ANY containing the application token
364  * bytes 0,1 are the token type
365  * bytes 2,n are the token data
366  *
367  * Note that the token type field is a feature of RFC 1964 mechanisms and
368  * is not used by other GSSAPI mechanisms.  As such, a token type of -1
369  * is interpreted to mean that no token type should be expected or
370  * generated.
371  *
372  * For the purposes of this abstraction, the token "header" consists of
373  * the sequence tag and length octets, the mech OID DER encoding, and the
374  * first two inner bytes, which indicate the token type.  The token
375  * "body" consists of everything else.
376  */
377
378 static size_t
379 der_length_size(size_t length)
380 {
381     if (length < (1<<7))
382         return 1;
383     else if (length < (1<<8))
384         return 2;
385 #if INT_MAX == 0x7fff
386     else
387         return 3;
388 #else
389     else if (length < (1<<16))
390         return 3;
391     else if (length < (1<<24))
392         return 4;
393     else
394         return 5;
395 #endif
396 }
397
398 static void
399 der_write_length(unsigned char **buf, size_t length)
400 {
401     if (length < (1<<7)) {
402         *(*buf)++ = (unsigned char)length;
403     } else {
404         *(*buf)++ = (unsigned char)(der_length_size(length)+127);
405 #if INT_MAX > 0x7fff
406         if (length >= (1<<24))
407             *(*buf)++ = (unsigned char)(length>>24);
408         if (length >= (1<<16))
409             *(*buf)++ = (unsigned char)((length>>16)&0xff);
410 #endif
411         if (length >= (1<<8))
412             *(*buf)++ = (unsigned char)((length>>8)&0xff);
413         *(*buf)++ = (unsigned char)(length&0xff);
414     }
415 }
416
417 /* returns decoded length, or < 0 on failure.  Advances buf and
418    decrements bufsize */
419
420 static int
421 der_read_length(unsigned char **buf, ssize_t *bufsize)
422 {
423     unsigned char sf;
424     int ret;
425
426     if (*bufsize < 1)
427         return -1;
428
429     sf = *(*buf)++;
430     (*bufsize)--;
431     if (sf & 0x80) {
432         if ((sf &= 0x7f) > ((*bufsize)-1))
433             return -1;
434         if (sf > sizeof(int))
435             return -1;
436         ret = 0;
437         for (; sf; sf--) {
438             ret = (ret<<8) + (*(*buf)++);
439             (*bufsize)--;
440         }
441     } else {
442         ret = sf;
443     }
444
445     return ret;
446 }
447
448 /* returns the length of a token, given the mech oid and the body size */
449
450 size_t
451 tokenSize(size_t body_size)
452 {
453     return 1 + der_length_size(body_size) + body_size;
454 }
455
456 /* fills in a buffer with the token header.  The buffer is assumed to
457    be the right size.  buf is advanced past the token header */
458
459 void
460 makeTokenHeader(
461     size_t body_size,
462     unsigned char **buf)
463 {
464     *(*buf)++ = 0x60;
465     der_write_length(buf, body_size);
466 }
467
468 /*
469  * Given a buffer containing a token, reads and verifies the token,
470  * leaving buf advanced past the token header, and setting body_size
471  * to the number of remaining bytes.  Returns 0 on success,
472  * G_BAD_TOK_HEADER for a variety of errors, and G_WRONG_MECH if the
473  * mechanism in the token does not match the mech argument.  buf and
474  * *body_size are left unmodified on error.
475  */
476
477 OM_uint32
478 verifyTokenHeader(OM_uint32 *minor,
479                   gss_OID mech,
480                   size_t *body_size,
481                   unsigned char **buf_in,
482                   size_t toksize_in,
483                   enum gss_eap_token_type *ret_tok_type)
484 {
485     unsigned char *buf = *buf_in;
486     ssize_t seqsize;
487     gss_OID_desc toid;
488     ssize_t toksize = (ssize_t)toksize_in;
489
490     *minor = GSSEAP_BAD_TOK_HEADER;
491
492     if (ret_tok_type != NULL)
493         *ret_tok_type = TOK_TYPE_NONE;
494
495     if ((toksize -= 1) < 0)
496         return GSS_S_DEFECTIVE_TOKEN;
497
498     if (*buf++ != 0x60)
499         return GSS_S_DEFECTIVE_TOKEN;
500
501     seqsize = der_read_length(&buf, &toksize);
502     if (seqsize < 0)
503         return GSS_S_DEFECTIVE_TOKEN;
504
505     if (seqsize != toksize)
506         return GSS_S_DEFECTIVE_TOKEN;
507
508     if ((toksize -= 1) < 0)
509         return GSS_S_DEFECTIVE_TOKEN;
510
511     if (*buf++ != 0x06)
512         return GSS_S_DEFECTIVE_TOKEN;
513
514     if ((toksize -= 1) < 0)
515         return GSS_S_DEFECTIVE_TOKEN;
516
517     toid.length = *buf++;
518
519     if ((toksize -= toid.length) < 0)
520         return GSS_S_DEFECTIVE_TOKEN;
521
522     toid.elements = buf;
523     buf += toid.length;
524
525     if (mech->elements == NULL) {
526         *mech = toid;
527         if (toid.length == 0)
528             return GSS_S_BAD_MECH;
529     } else if (!oidEqual(&toid, mech)) {
530         *minor = GSSEAP_WRONG_MECH;
531         return GSS_S_BAD_MECH;
532     }
533
534     if (ret_tok_type != NULL) {
535         if ((toksize -= 2) < 0)
536             return GSS_S_DEFECTIVE_TOKEN;
537
538         *ret_tok_type = load_uint16_be(buf);
539         buf += 2;
540     }
541
542     *buf_in = buf;
543     *body_size = toksize;
544
545     *minor = 0;
546     return GSS_S_COMPLETE;
547 }