1 /*
2  * Copyright (c) 2011, PADL Software Pty Ltd.
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 PADL Software 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 PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
21  * 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 PADL SOFTWARE 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 #include <config.h>
55 #include <string.h>
56 #include <stdlib.h>
57 
58 #include "gs2_token.h"
59 
60 #ifndef HAVE_GSS_ENCAPSULATE_TOKEN
61 /* XXXX this code currently makes the assumption that a mech oid will
62    never be longer than 127 bytes.  This assumption is not inherent in
63    the interfaces, so the code can be fixed if the OSI namespace
64    balloons unexpectedly. */
65 
66 /*
67  * Each token looks like this:
68  * 0x60                 tag for APPLICATION 0, SEQUENCE
69  *                              (constructed, definite-length)
70  * <length>             possible multiple bytes, need to parse/generate
71  * 0x06                 tag for OBJECT IDENTIFIER
72  * <moid_length>        compile-time constant string (assume 1 byte)
73  * <moid_bytes>         compile-time constant string
74  * <inner_bytes>        the ANY containing the application token
75  * bytes 0,1 are the token type
76  * bytes 2,n are the token data
77  *
78  * Note that the token type field is a feature of RFC 1964 mechanisms and
79  * is not used by other GSSAPI mechanisms.  As such, a token type of -1
80  * is interpreted to mean that no token type should be expected or
81  * generated.
82  *
83  * For the purposes of this abstraction, the token "header" consists of
84  * the sequence tag and length octets, the mech OID DER encoding, and the
85  * first two inner bytes, which indicate the token type.  The token
86  * "body" consists of everything else.
87  */
88 
89 static size_t
der_length_size(size_t length)90 der_length_size(size_t length)
91 {
92     if (length < (1<<7))
93         return 1;
94     else if (length < (1<<8))
95         return 2;
96 #if INT_MAX == 0x7fff
97     else
98         return 3;
99 #else
100     else if (length < (1<<16))
101         return 3;
102     else if (length < (1<<24))
103         return 4;
104     else
105         return 5;
106 #endif
107 }
108 
109 static void
der_write_length(unsigned char ** buf,size_t length)110 der_write_length(unsigned char **buf, size_t length)
111 {
112     if (length < (1<<7)) {
113         *(*buf)++ = (unsigned char)length;
114     } else {
115         *(*buf)++ = (unsigned char)(der_length_size(length)+127);
116 #if INT_MAX > 0x7fff
117         if (length >= (1<<24))
118             *(*buf)++ = (unsigned char)(length>>24);
119         if (length >= (1<<16))
120             *(*buf)++ = (unsigned char)((length>>16)&0xff);
121 #endif
122         if (length >= (1<<8))
123             *(*buf)++ = (unsigned char)((length>>8)&0xff);
124         *(*buf)++ = (unsigned char)(length&0xff);
125     }
126 }
127 
128 /* returns the length of a token, given the mech oid and the body size */
129 
130 static size_t
token_size(const gss_OID_desc * mech,size_t body_size)131 token_size(const gss_OID_desc *mech, size_t body_size)
132 {
133     /* set body_size to sequence contents size */
134     body_size += 2 + (size_t) mech->length;         /* NEED overflow check */
135     return 1 + der_length_size(body_size) + body_size;
136 }
137 
138 /* fills in a buffer with the token header.  The buffer is assumed to
139    be the right size.  buf is advanced past the token header */
140 
141 static void
make_token_header(const gss_OID_desc * mech,size_t body_size,unsigned char ** buf)142 make_token_header(
143     const gss_OID_desc *mech,
144     size_t body_size,
145     unsigned char **buf)
146 {
147     *(*buf)++ = 0x60;
148     der_write_length(buf, 2 + mech->length + body_size);
149     *(*buf)++ = 0x06;
150     *(*buf)++ = (unsigned char)mech->length;
151     memcpy(*buf, mech->elements, mech->length);
152     *buf += mech->length;
153 }
154 
155 OM_uint32
gs2_encapsulate_token(const gss_buffer_t input_token,const gss_OID token_oid,gss_buffer_t output_token)156 gs2_encapsulate_token(const gss_buffer_t input_token,
157                       const gss_OID token_oid,
158                       gss_buffer_t output_token)
159 {
160     size_t tokenSize;
161     unsigned char *buf;
162 
163     if (input_token == GSS_C_NO_BUFFER || token_oid == GSS_C_NO_OID)
164         return GSS_S_CALL_INACCESSIBLE_READ;
165 
166     if (output_token == GSS_C_NO_BUFFER)
167         return GSS_S_CALL_INACCESSIBLE_WRITE;
168 
169     tokenSize = token_size(token_oid, input_token->length);
170 
171     output_token->value = malloc(tokenSize);
172     if (output_token->value == NULL)
173         return GSS_S_FAILURE;
174 
175     buf = output_token->value;
176 
177     make_token_header(token_oid, input_token->length, &buf);
178     memcpy(buf, input_token->value, input_token->length);
179     output_token->length = tokenSize;
180 
181     return GSS_S_COMPLETE;
182 }
183 #endif
184 
185 
186 #ifndef HAVE_GSS_DECAPSULATE_TOKEN
187 /* returns decoded length, or < 0 on failure.  Advances buf and
188    decrements bufsize */
189 
190 static int
der_read_length(unsigned char ** buf,ssize_t * bufsize)191 der_read_length(unsigned char **buf, ssize_t *bufsize)
192 {
193     unsigned char sf;
194     int ret;
195 
196     if (*bufsize < 1)
197         return -1;
198 
199     sf = *(*buf)++;
200     (*bufsize)--;
201     if (sf & 0x80) {
202         if ((sf &= 0x7f) > ((*bufsize)-1))
203             return -1;
204         if (sf > sizeof(int))
205             return -1;
206         ret = 0;
207         for (; sf; sf--) {
208             ret = (ret<<8) + (*(*buf)++);
209             (*bufsize)--;
210         }
211     } else {
212         ret = sf;
213     }
214 
215     return ret;
216 }
217 
218 /*
219  * Given a buffer containing a token, reads and verifies the token,
220  * leaving buf advanced past the token header, and setting body_size
221  * to the number of remaining bytes.  Returns 0 on success,
222  * G_BAD_TOK_HEADER for a variety of errors, and G_WRONG_MECH if the
223  * mechanism in the token does not match the mech argument.  buf and
224  * *body_size are left unmodified on error.
225  */
226 
227 static OM_uint32
verify_token_header(OM_uint32 * minor,const gss_OID mech,size_t * body_size,unsigned char ** buf_in,size_t toksize_in)228 verify_token_header(OM_uint32 *minor,
229                     const gss_OID mech,
230                     size_t *body_size,
231                     unsigned char **buf_in,
232                     size_t toksize_in)
233 {
234     unsigned char *buf = *buf_in;
235     ssize_t seqsize;
236     gss_OID_desc toid;
237     ssize_t toksize = (ssize_t)toksize_in;
238 
239     *minor = 0;
240 
241     if ((toksize -= 1) < 0)
242         return GSS_S_DEFECTIVE_TOKEN;
243 
244     if (*buf++ != 0x60)
245         return GSS_S_DEFECTIVE_TOKEN;
246 
247     seqsize = der_read_length(&buf, &toksize);
248     if (seqsize < 0)
249         return GSS_S_DEFECTIVE_TOKEN;
250 
251     if (seqsize != toksize)
252         return GSS_S_DEFECTIVE_TOKEN;
253 
254     if ((toksize -= 1) < 0)
255         return GSS_S_DEFECTIVE_TOKEN;
256 
257     if (*buf++ != 0x06)
258         return GSS_S_DEFECTIVE_TOKEN;
259 
260     if ((toksize -= 1) < 0)
261         return GSS_S_DEFECTIVE_TOKEN;
262 
263     toid.length = *buf++;
264 
265     if ((toksize -= toid.length) < 0)
266         return GSS_S_DEFECTIVE_TOKEN;
267 
268     toid.elements = buf;
269     buf += toid.length;
270 
271     if (!gss_oid_equal(&toid, mech))
272         return GSS_S_DEFECTIVE_TOKEN;
273 
274     *buf_in = buf;
275     *body_size = toksize;
276 
277     return GSS_S_COMPLETE;
278 }
279 
280 OM_uint32
gs2_decapsulate_token(const gss_buffer_t input_token,const gss_OID token_oid,gss_buffer_t output_token)281 gs2_decapsulate_token(const gss_buffer_t input_token,
282                       const gss_OID token_oid,
283                       gss_buffer_t output_token)
284 {
285     OM_uint32 major, minor;
286     size_t body_size = 0;
287     unsigned char *buf_in;
288 
289     if (input_token == GSS_C_NO_BUFFER || token_oid == GSS_C_NO_OID)
290         return GSS_S_CALL_INACCESSIBLE_READ;
291 
292     if (output_token == GSS_C_NO_BUFFER)
293         return GSS_S_CALL_INACCESSIBLE_WRITE;
294 
295     buf_in = input_token->value;
296 
297     major = verify_token_header(&minor, token_oid, &body_size, &buf_in,
298                                 input_token->length);
299     if (minor != 0)
300         return GSS_S_DEFECTIVE_TOKEN;
301 
302     output_token->value = malloc(body_size);
303     if (output_token->value == NULL)
304         return GSS_S_FAILURE;
305 
306     memcpy(output_token->value, buf_in, body_size);
307     output_token->length = body_size;
308 
309     return GSS_S_COMPLETE;
310 }
311 #endif
312 
313 #ifndef HAVE_GSS_OID_EQUAL
314 int
gs2_oid_equal(const gss_OID o1,const gss_OID o2)315 gs2_oid_equal(const gss_OID o1, const gss_OID o2)
316 {
317     return o1->length == o2->length &&
318         (memcmp(o1->elements, o2->elements, o1->length) == 0);
319 }
320 #endif
321