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