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