Home | History | Annotate | Download | only in mech
      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