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  * SUNW14resync
28  * This is defed in autoconf but we don't grok it for kernel (why?).
29  */
30 #ifndef SIZEOF_INT
31 #define SIZEOF_INT 4
32 #endif
33 
34 /*
35  * $Id: util_token.c,v 1.20.2.1 2003/12/16 02:56:16 tlyu Exp $
36  */
37 
38 /* XXXX this code currently makes the assumption that a mech oid will
39    never be longer than 127 bytes.  This assumption is not inherent in
40    the interfaces, so the code can be fixed if the OSI namespace
41    balloons unexpectedly. */
42 
43 /* Each token looks like this:
44 
45 0x60				tag for APPLICATION 0, SEQUENCE
46 					(constructed, definite-length)
47 	<length>		possible multiple bytes, need to parse/generate
48 	0x06			tag for OBJECT IDENTIFIER
49 		<moid_length>	compile-time constant string (assume 1 byte)
50 		<moid_bytes>	compile-time constant string
51 	<inner_bytes>		the ANY containing the application token
52 					bytes 0,1 are the token type
53 					bytes 2,n are the token data
54 
55 Note that the token type field is a feature of RFC 1964 mechanisms and
56 is not used by other GSSAPI mechanisms.	 As such, a token type of -1
57 is interpreted to mean that no token type should be expected or
58 generated.
59 
60 For the purposes of this abstraction, the token "header" consists of
61 the sequence tag and length octets, the mech OID DER encoding, and the
62 first two inner bytes, which indicate the token type.  The token
63 "body" consists of everything else.
64 
65 */
66 
67 static int der_length_size(length)
68      int length;
69 {
70    if (length < (1<<7))
71       return(1);
72    else if (length < (1<<8))
73       return(2);
74 #if (SIZEOF_INT == 2)
75    else
76        return(3);
77 #else
78    else if (length < (1<<16))
79       return(3);
80    else if (length < (1<<24))
81       return(4);
82    else
83       return(5);
84 #endif
85 }
86 
87 static void der_write_length(buf, length)
88      unsigned char **buf;
89      int length;
90 {
91    if (length < (1<<7)) {
92       *(*buf)++ = (unsigned char) length;
93    } else {
94       *(*buf)++ = (unsigned char) (der_length_size(length)+127);
95 #if (SIZEOF_INT > 2)
96       if (length >= (1<<24))
97 	 *(*buf)++ = (unsigned char) (length>>24);
98       if (length >= (1<<16))
99 	 *(*buf)++ = (unsigned char) ((length>>16)&0xff);
100 #endif
101       if (length >= (1<<8))
102 	 *(*buf)++ = (unsigned char) ((length>>8)&0xff);
103       *(*buf)++ = (unsigned char) (length&0xff);
104    }
105 }
106 
107 /* returns decoded length, or < 0 on failure.  Advances buf and
108    decrements bufsize */
109 
110 static int der_read_length(buf, bufsize)
111      unsigned char **buf;
112      int *bufsize;
113 {
114    unsigned char sf;
115    int ret;
116 
117    if (*bufsize < 1)
118       return(-1);
119    sf = *(*buf)++;
120    (*bufsize)--;
121    if (sf & 0x80) {
122       if ((sf &= 0x7f) > ((*bufsize)-1))
123 	 return(-1);
124       if (sf > SIZEOF_INT)
125 	  return (-1);
126       ret = 0;
127       for (; sf; sf--) {
128 	 ret = (ret<<8) + (*(*buf)++);
129 	 (*bufsize)--;
130       }
131    } else {
132       ret = sf;
133    }
134 
135    return(ret);
136 }
137 
138 /* returns the length of a token, given the mech oid and the body size */
139 
140 int g_token_size(mech, body_size)
141      gss_OID mech;
142      unsigned int body_size;
143 {
144    /* set body_size to sequence contents size */
145    body_size += 4 + (int) mech->length;         /* NEED overflow check */
146    return(1 + der_length_size((int) body_size) + body_size);
147 }
148 
149 /* fills in a buffer with the token header.  The buffer is assumed to
150    be the right size.  buf is advanced past the token header */
151 
152 void g_make_token_header(mech, body_size, buf, tok_type)
153      gss_OID mech;
154      int body_size;
155      unsigned char **buf;
156      int tok_type;
157 {
158    *(*buf)++ = 0x60;
159    der_write_length(buf, (int) (4 + mech->length + body_size));
160    *(*buf)++ = 0x06;
161    *(*buf)++ = (unsigned char) mech->length;
162    TWRITE_STR(*buf, mech->elements, ((int) mech->length));
163    if (tok_type != -1) {
164 	*(*buf)++ = (unsigned char) ((tok_type>>8)&0xff);
165 	*(*buf)++ = (unsigned char) (tok_type&0xff);
166    }
167 }
168 
169 /*
170  * Given a buffer containing a token, reads and verifies the token,
171  * leaving buf advanced past the token header, and setting body_size
172  * to the number of remaining bytes.  Returns 0 on success,
173  * G_BAD_TOK_HEADER for a variety of errors, and G_WRONG_MECH if the
174  * mechanism in the token does not match the mech argument.  buf and
175  * *body_size are left unmodified on error.
176  */
177 
178 gss_int32 g_verify_token_header(mech, body_size, buf_in, tok_type, toksize_in,
179 				wrapper_required)
180 	gss_OID mech;
181 	unsigned int *body_size;
182 	unsigned char **buf_in;
183 	int tok_type;
184 	unsigned int toksize_in;
185 	int wrapper_required;
186 {
187    unsigned char *buf = *buf_in;
188    int seqsize;
189    gss_OID_desc toid;
190    int toksize = toksize_in;
191 
192    if ((toksize-=1) < 0)
193 	return(G_BAD_TOK_HEADER);
194    if (*buf++ != 0x60) {
195 	if (wrapper_required)
196 	   return(G_BAD_TOK_HEADER);
197 	buf--;
198 	toksize++;
199 	goto skip_wrapper;
200    }
201 
202    if ((seqsize = der_read_length(&buf, &toksize)) < 0)
203 	return(G_BAD_TOK_HEADER);
204 
205    if (seqsize != toksize)
206 	return(G_BAD_TOK_HEADER);
207 
208    if ((toksize-=1) < 0)
209 	return(G_BAD_TOK_HEADER);
210    if (*buf++ != 0x06)
211 	return(G_BAD_TOK_HEADER);
212 
213    if ((toksize-=1) < 0)
214 	return(G_BAD_TOK_HEADER);
215    toid.length = *buf++;
216 
217    if ((toksize-=toid.length) < 0)
218 	return(G_BAD_TOK_HEADER);
219    toid.elements = buf;
220    buf+=toid.length;
221 
222    if (! g_OID_equal(&toid, mech))
223 	return  G_WRONG_MECH;
224 skip_wrapper:
225    if (tok_type != -1) {
226 	if ((toksize-=2) < 0)
227 	   return(G_BAD_TOK_HEADER);
228 
229 	if ((*buf++ != ((tok_type>>8)&0xff)) ||
230 	   (*buf++ != (tok_type&0xff)))
231 	   return(G_WRONG_TOKID);
232    }
233    *buf_in = buf;
234    *body_size = toksize;
235 
236    return 0;
237 }
238 
239