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