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