5231ae2a52ddd0ded32de99b3c464fc03b52b888
[mech_eap.git] / 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  * 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 /*
61  * $Id: util_token.c 23457 2009-12-08 00:04:48Z tlyu $
62  */
63
64 /* XXXX this code currently makes the assumption that a mech oid will
65    never be longer than 127 bytes.  This assumption is not inherent in
66    the interfaces, so the code can be fixed if the OSI namespace
67    balloons unexpectedly. */
68
69 /*
70  * Each token looks like this:
71  * 0x60                 tag for APPLICATION 0, SEQUENCE
72  *                              (constructed, definite-length)
73  * <length>             possible multiple bytes, need to parse/generate
74  * 0x06                 tag for OBJECT IDENTIFIER
75  * <moid_length>        compile-time constant string (assume 1 byte)
76  * <moid_bytes>         compile-time constant string
77  * <inner_bytes>        the ANY containing the application token
78  * bytes 0,1 are the token type
79  * bytes 2,n are the token data
80  *
81  * Note that the token type field is a feature of RFC 1964 mechanisms and
82  * is not used by other GSSAPI mechanisms.  As such, a token type of -1
83  * is interpreted to mean that no token type should be expected or
84  * generated.
85  *
86  * For the purposes of this abstraction, the token "header" consists of
87  * the sequence tag and length octets, the mech OID DER encoding, and the
88  * first two inner bytes, which indicate the token type.  The token
89  * "body" consists of everything else.
90  */
91
92 static size_t
93 der_length_size(size_t length)
94 {
95     if (length < (1<<7))
96         return 1;
97     else if (length < (1<<8))
98         return 2;
99 #if INT_MAX == 0x7fff
100     else
101         return 3;
102 #else
103     else if (length < (1<<16))
104         return 3;
105     else if (length < (1<<24))
106         return 4;
107     else
108         return 5;
109 #endif
110 }
111
112 static void
113 der_write_length(unsigned char **buf, size_t length)
114 {
115     if (length < (1<<7)) {
116         *(*buf)++ = (unsigned char)length;
117     } else {
118         *(*buf)++ = (unsigned char)(der_length_size(length)+127);
119 #if INT_MAX > 0x7fff
120         if (length >= (1<<24))
121             *(*buf)++ = (unsigned char)(length>>24);
122         if (length >= (1<<16))
123             *(*buf)++ = (unsigned char)((length>>16)&0xff);
124 #endif
125         if (length >= (1<<8))
126             *(*buf)++ = (unsigned char)((length>>8)&0xff);
127         *(*buf)++ = (unsigned char)(length&0xff);
128     }
129 }
130
131 /* returns decoded length, or < 0 on failure.  Advances buf and
132    decrements bufsize */
133
134 static int
135 der_read_length(unsigned char **buf, ssize_t *bufsize)
136 {
137     unsigned char sf;
138     int ret;
139
140     if (*bufsize < 1)
141         return -1;
142
143     sf = *(*buf)++;
144     (*bufsize)--;
145     if (sf & 0x80) {
146         if ((sf &= 0x7f) > ((*bufsize)-1))
147             return -1;
148         if (sf > sizeof(int))
149             return -1;
150         ret = 0;
151         for (; sf; sf--) {
152             ret = (ret<<8) + (*(*buf)++);
153             (*bufsize)--;
154         }
155     } else {
156         ret = sf;
157     }
158
159     return ret;
160 }
161
162 /* returns the length of a token, given the mech oid and the body size */
163
164 size_t
165 tokenSize(const gss_OID_desc *mech, size_t body_size)
166 {
167     /* set body_size to sequence contents size */
168     body_size += 4 + (size_t) mech->length;         /* NEED overflow check */
169     return 1 + der_length_size(body_size) + body_size;
170 }
171
172 /* fills in a buffer with the token header.  The buffer is assumed to
173    be the right size.  buf is advanced past the token header */
174
175 void
176 makeTokenHeader(
177     const gss_OID_desc *mech,
178     size_t body_size,
179     unsigned char **buf,
180     enum gss_eap_token_type tok_type)
181 {
182     *(*buf)++ = 0x60;
183     der_write_length(buf, (tok_type == -1) ?2:4 + mech->length + body_size);
184     *(*buf)++ = 0x06;
185     *(*buf)++ = (unsigned char)mech->length;
186     memcpy(*buf, mech->elements, mech->length);
187     *buf += mech->length;
188     assert(tok_type != TOK_TYPE_NONE);
189     *(*buf)++ = (unsigned char)((tok_type>>8) & 0xff);
190     *(*buf)++ = (unsigned char)(tok_type & 0xff);
191 }
192
193 /*
194  * Given a buffer containing a token, reads and verifies the token,
195  * leaving buf advanced past the token header, and setting body_size
196  * to the number of remaining bytes.  Returns 0 on success,
197  * G_BAD_TOK_HEADER for a variety of errors, and G_WRONG_MECH if the
198  * mechanism in the token does not match the mech argument.  buf and
199  * *body_size are left unmodified on error.
200  */
201
202 OM_uint32
203 verifyTokenHeader(OM_uint32 *minor,
204                   gss_OID mech,
205                   size_t *body_size,
206                   unsigned char **buf_in,
207                   size_t toksize_in,
208                   enum gss_eap_token_type *ret_tok_type)
209 {
210     unsigned char *buf = *buf_in;
211     ssize_t seqsize;
212     gss_OID_desc toid;
213     ssize_t toksize = (ssize_t)toksize_in;
214
215     *minor = GSSEAP_BAD_TOK_HEADER;
216
217     if (ret_tok_type != NULL)
218         *ret_tok_type = TOK_TYPE_NONE;
219
220     if ((toksize -= 1) < 0)
221         return GSS_S_DEFECTIVE_TOKEN;
222
223     if (*buf++ != 0x60)
224         return GSS_S_DEFECTIVE_TOKEN;
225
226     seqsize = der_read_length(&buf, &toksize);
227     if (seqsize < 0)
228         return GSS_S_DEFECTIVE_TOKEN;
229
230     if (seqsize != toksize)
231         return GSS_S_DEFECTIVE_TOKEN;
232
233     if ((toksize -= 1) < 0)
234         return GSS_S_DEFECTIVE_TOKEN;
235
236     if (*buf++ != 0x06)
237         return GSS_S_DEFECTIVE_TOKEN;
238
239     if ((toksize -= 1) < 0)
240         return GSS_S_DEFECTIVE_TOKEN;
241
242     toid.length = *buf++;
243
244     if ((toksize -= toid.length) < 0)
245         return GSS_S_DEFECTIVE_TOKEN;
246
247     toid.elements = buf;
248     buf += toid.length;
249
250     if (mech->elements == NULL) {
251         *mech = toid;
252         if (toid.length == 0)
253             return GSS_S_BAD_MECH;
254     } else if (!oidEqual(&toid, mech)) {
255         *minor = GSSEAP_WRONG_MECH;
256         return GSS_S_BAD_MECH;
257     }
258
259     if (ret_tok_type != NULL) {
260         if ((toksize -= 2) < 0)
261             return GSS_S_DEFECTIVE_TOKEN;
262
263         *ret_tok_type = load_uint16_be(buf);
264         buf += 2;
265     }
266
267     *buf_in = buf;
268     *body_size = toksize;
269
270     *minor = 0;
271     return GSS_S_COMPLETE;
272 }