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 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 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 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 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 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 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