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
der_length_size(length)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
der_write_length(buf,length)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
der_read_length(buf,bufsize)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
g_token_size(mech,body_size)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
g_make_token_header(mech,body_size,buf,tok_type)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
g_verify_token_header(mech,body_size,buf_in,tok_type,toksize_in,wrapper_required)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