1 /*
2  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
7 
8 /*
9  * Copyright 1993 by OpenVision Technologies, Inc.
10  *
11  * Permission to use, copy, modify, distribute, and sell this software
12  * and its documentation for any purpose is hereby granted without fee,
13  * provided that the above copyright notice appears in all copies and
14  * that both that copyright notice and this permission notice appear in
15  * supporting documentation, and that the name of OpenVision not be used
16  * in advertising or publicity pertaining to distribution of the software
17  * without specific, written prior permission. OpenVision makes no
18  * representations about the suitability of this software for any
19  * purpose.  It is provided "as is" without express or implied warranty.
20  *
21  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
22  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
23  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
24  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
25  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
26  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
27  * PERFORMANCE OF THIS SOFTWARE.
28  */
29 
30 #include "gssapiP_generic.h"
31 
32 #ifdef _KERNEL
33 #include <sys/systm.h>
34 #else
35 #ifdef HAVE_MEMORY_H
36 #include <memory.h>
37 #endif
38 #include <limits.h>
39 #include <string.h>
40 #endif /* _KERNEL */
41 
42 
43 /*
44  * $Id: util_token.c 17987 2006-05-09 11:31:02Z epeisach $
45  */
46 
47 /* XXXX this code currently makes the assumption that a mech oid will
48    never be longer than 127 bytes.  This assumption is not inherent in
49    the interfaces, so the code can be fixed if the OSI namespace
50    balloons unexpectedly. */
51 
52 /* Each token looks like this:
53 
54 0x60				tag for APPLICATION 0, SEQUENCE
55 					(constructed, definite-length)
56 	<length>		possible multiple bytes, need to parse/generate
57 	0x06			tag for OBJECT IDENTIFIER
58 		<moid_length>	compile-time constant string (assume 1 byte)
59 		<moid_bytes>	compile-time constant string
60 	<inner_bytes>		the ANY containing the application token
61 					bytes 0,1 are the token type
62 					bytes 2,n are the token data
63 
64 Note that the token type field is a feature of RFC 1964 mechanisms and
65 is not used by other GSSAPI mechanisms.  As such, a token type of -1
66 is interpreted to mean that no token type should be expected or
67 generated.
68 
69 For the purposes of this abstraction, the token "header" consists of
70 the sequence tag and length octets, the mech OID DER encoding, and the
71 first two inner bytes, which indicate the token type.  The token
72 "body" consists of everything else.
73 
74 */
75 
76 static unsigned int der_length_size(length)
77      int length;
78 {
79    if (length < (1<<7))
80       return(1);
81    else if (length < (1<<8))
82       return(2);
83 #if INT_MAX == 0x7fff
84    else
85        return(3);
86 #else
87    else if (length < (1<<16))
88       return(3);
89    else if (length < (1<<24))
90       return(4);
91    else
92       return(5);
93 #endif
94 }
95 
96 static void der_write_length(buf, length)
97      unsigned char **buf;
98      int length;
99 {
100    if (length < (1<<7)) {
101       *(*buf)++ = (unsigned char) length;
102    } else {
103       *(*buf)++ = (unsigned char) (der_length_size(length)+127);
104 #if INT_MAX > 0x7fff
105       if (length >= (1<<24))
106 	 *(*buf)++ = (unsigned char) (length>>24);
107       if (length >= (1<<16))
108 	 *(*buf)++ = (unsigned char) ((length>>16)&0xff);
109 #endif
110       if (length >= (1<<8))
111 	 *(*buf)++ = (unsigned char) ((length>>8)&0xff);
112       *(*buf)++ = (unsigned char) (length&0xff);
113    }
114 }
115 
116 /* returns decoded length, or < 0 on failure.  Advances buf and
117    decrements bufsize */
118 
119 static int der_read_length(buf, bufsize)
120      unsigned char **buf;
121      int *bufsize;
122 {
123    unsigned char sf;
124    int ret;
125 
126    if (*bufsize < 1)
127       return(-1);
128    sf = *(*buf)++;
129    (*bufsize)--;
130    if (sf & 0x80) {
131       if ((sf &= 0x7f) > ((*bufsize)-1))
132 	 return(-1);
133       if (sf > sizeof(int))
134 	  return (-1);
135       ret = 0;
136       for (; sf; sf--) {
137 	 ret = (ret<<8) + (*(*buf)++);
138 	 (*bufsize)--;
139       }
140    } else {
141       ret = sf;
142    }
143 
144    return(ret);
145 }
146 
147 /* returns the length of a token, given the mech oid and the body size */
148 
149 unsigned int g_token_size(mech, body_size)
150      const gss_OID_desc * mech;
151      unsigned int body_size;
152 {
153    /* set body_size to sequence contents size */
154    body_size += 4 + (int) mech->length;         /* NEED overflow check */
155    return(1 + der_length_size((int) body_size) + body_size);
156 }
157 
158 /* fills in a buffer with the token header.  The buffer is assumed to
159    be the right size.  buf is advanced past the token header */
160 
161 void g_make_token_header(mech, body_size, buf, tok_type)
162      const gss_OID_desc * mech;
163      unsigned int body_size;
164      unsigned char **buf;
165      int tok_type;
166 {
167    *(*buf)++ = 0x60;
168    der_write_length(buf,
169        (tok_type == -1) ? 2 : (int) (4 + mech->length + body_size));
170    *(*buf)++ = 0x06;
171    *(*buf)++ = (unsigned char) mech->length;
172    TWRITE_STR(*buf, mech->elements, mech->length);
173    if (tok_type != -1) {
174        *(*buf)++ = (unsigned char) ((tok_type>>8)&0xff);
175        *(*buf)++ = (unsigned char) (tok_type&0xff);
176    }
177 }
178 
179 /*
180  * Given a buffer containing a token, reads and verifies the token,
181  * leaving buf advanced past the token header, and setting body_size
182  * to the number of remaining bytes.  Returns 0 on success,
183  * G_BAD_TOK_HEADER for a variety of errors, and G_WRONG_MECH if the
184  * mechanism in the token does not match the mech argument.  buf and
185  * *body_size are left unmodified on error.
186  */
187 
188 gss_int32 g_verify_token_header(mech, body_size, buf_in, tok_type, toksize_in,
189 				wrapper_required)
190      const gss_OID_desc * mech;
191      unsigned int *body_size;
192      unsigned char **buf_in;
193      int tok_type;
194      unsigned int toksize_in;
195      int wrapper_required;
196 {
197    unsigned char *buf = *buf_in;
198    int seqsize;
199    gss_OID_desc toid;
200    int toksize = toksize_in;
201 
202    if ((toksize-=1) < 0)
203       return(G_BAD_TOK_HEADER);
204    if (*buf++ != 0x60) {
205        if (wrapper_required)
206 	   return(G_BAD_TOK_HEADER);
207        buf--;
208        toksize++;
209        goto skip_wrapper;
210    }
211 
212    if ((seqsize = der_read_length(&buf, &toksize)) < 0)
213       return(G_BAD_TOK_HEADER);
214 
215    if (seqsize != toksize)
216       return(G_BAD_TOK_HEADER);
217 
218    if ((toksize-=1) < 0)
219       return(G_BAD_TOK_HEADER);
220    if (*buf++ != 0x06)
221       return(G_BAD_TOK_HEADER);
222 
223    if ((toksize-=1) < 0)
224       return(G_BAD_TOK_HEADER);
225    toid.length = *buf++;
226 
227    if ((toksize-=toid.length) < 0)
228       return(G_BAD_TOK_HEADER);
229    toid.elements = buf;
230    buf+=toid.length;
231 
232    if (! g_OID_equal(&toid, mech))
233        return  G_WRONG_MECH;
234 skip_wrapper:
235    if (tok_type != -1) {
236        if ((toksize-=2) < 0)
237 	   return(G_BAD_TOK_HEADER);
238 
239        if ((*buf++ != ((tok_type>>8)&0xff)) ||
240 	   (*buf++ != (tok_type&0xff)))
241 	   return(G_WRONG_TOKID);
242    }
243    *buf_in = buf;
244    *body_size = toksize;
245 
246    return 0;
247 }
248