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