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