xref: /onnv-gate/usr/src/uts/common/gssapi/mechs/krb5/mech/util_token.c (revision 5053:532e59d6bffd)
1*5053Sgtb /*
2*5053Sgtb  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
3*5053Sgtb  * Use is subject to license terms.
4*5053Sgtb  */
5*5053Sgtb 
60Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
7*5053Sgtb 
80Sstevel@tonic-gate /*
90Sstevel@tonic-gate  * Copyright 1993 by OpenVision Technologies, Inc.
100Sstevel@tonic-gate  *
110Sstevel@tonic-gate  * Permission to use, copy, modify, distribute, and sell this software
120Sstevel@tonic-gate  * and its documentation for any purpose is hereby granted without fee,
130Sstevel@tonic-gate  * provided that the above copyright notice appears in all copies and
140Sstevel@tonic-gate  * that both that copyright notice and this permission notice appear in
150Sstevel@tonic-gate  * supporting documentation, and that the name of OpenVision not be used
160Sstevel@tonic-gate  * in advertising or publicity pertaining to distribution of the software
170Sstevel@tonic-gate  * without specific, written prior permission. OpenVision makes no
180Sstevel@tonic-gate  * representations about the suitability of this software for any
190Sstevel@tonic-gate  * purpose.  It is provided "as is" without express or implied warranty.
200Sstevel@tonic-gate  *
210Sstevel@tonic-gate  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
220Sstevel@tonic-gate  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
230Sstevel@tonic-gate  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
240Sstevel@tonic-gate  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
250Sstevel@tonic-gate  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
260Sstevel@tonic-gate  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
270Sstevel@tonic-gate  * PERFORMANCE OF THIS SOFTWARE.
280Sstevel@tonic-gate  */
290Sstevel@tonic-gate 
30*5053Sgtb #include "gssapiP_generic.h"
31*5053Sgtb 
32*5053Sgtb #ifdef _KERNEL
33*5053Sgtb #include <sys/systm.h>
34*5053Sgtb #else
35*5053Sgtb #ifdef HAVE_MEMORY_H
36*5053Sgtb #include <memory.h>
37*5053Sgtb #endif
38*5053Sgtb #include <limits.h>
39*5053Sgtb #include <string.h>
40*5053Sgtb #endif /* _KERNEL */
41*5053Sgtb 
420Sstevel@tonic-gate 
430Sstevel@tonic-gate /*
44*5053Sgtb  * $Id: util_token.c 17987 2006-05-09 11:31:02Z epeisach $
450Sstevel@tonic-gate  */
460Sstevel@tonic-gate 
470Sstevel@tonic-gate /* XXXX this code currently makes the assumption that a mech oid will
480Sstevel@tonic-gate    never be longer than 127 bytes.  This assumption is not inherent in
490Sstevel@tonic-gate    the interfaces, so the code can be fixed if the OSI namespace
500Sstevel@tonic-gate    balloons unexpectedly. */
510Sstevel@tonic-gate 
520Sstevel@tonic-gate /* Each token looks like this:
530Sstevel@tonic-gate 
540Sstevel@tonic-gate 0x60				tag for APPLICATION 0, SEQUENCE
550Sstevel@tonic-gate 					(constructed, definite-length)
560Sstevel@tonic-gate 	<length>		possible multiple bytes, need to parse/generate
570Sstevel@tonic-gate 	0x06			tag for OBJECT IDENTIFIER
580Sstevel@tonic-gate 		<moid_length>	compile-time constant string (assume 1 byte)
590Sstevel@tonic-gate 		<moid_bytes>	compile-time constant string
600Sstevel@tonic-gate 	<inner_bytes>		the ANY containing the application token
610Sstevel@tonic-gate 					bytes 0,1 are the token type
620Sstevel@tonic-gate 					bytes 2,n are the token data
630Sstevel@tonic-gate 
640Sstevel@tonic-gate Note that the token type field is a feature of RFC 1964 mechanisms and
65*5053Sgtb is not used by other GSSAPI mechanisms.  As such, a token type of -1
660Sstevel@tonic-gate is interpreted to mean that no token type should be expected or
67*5053Sgtb generated.
680Sstevel@tonic-gate 
690Sstevel@tonic-gate For the purposes of this abstraction, the token "header" consists of
700Sstevel@tonic-gate the sequence tag and length octets, the mech OID DER encoding, and the
710Sstevel@tonic-gate first two inner bytes, which indicate the token type.  The token
720Sstevel@tonic-gate "body" consists of everything else.
730Sstevel@tonic-gate 
740Sstevel@tonic-gate */
750Sstevel@tonic-gate 
der_length_size(length)76*5053Sgtb static unsigned int der_length_size(length)
770Sstevel@tonic-gate      int length;
780Sstevel@tonic-gate {
790Sstevel@tonic-gate    if (length < (1<<7))
800Sstevel@tonic-gate       return(1);
810Sstevel@tonic-gate    else if (length < (1<<8))
820Sstevel@tonic-gate       return(2);
83*5053Sgtb #if INT_MAX == 0x7fff
840Sstevel@tonic-gate    else
850Sstevel@tonic-gate        return(3);
860Sstevel@tonic-gate #else
870Sstevel@tonic-gate    else if (length < (1<<16))
880Sstevel@tonic-gate       return(3);
890Sstevel@tonic-gate    else if (length < (1<<24))
900Sstevel@tonic-gate       return(4);
910Sstevel@tonic-gate    else
920Sstevel@tonic-gate       return(5);
930Sstevel@tonic-gate #endif
940Sstevel@tonic-gate }
950Sstevel@tonic-gate 
der_write_length(buf,length)960Sstevel@tonic-gate static void der_write_length(buf, length)
970Sstevel@tonic-gate      unsigned char **buf;
980Sstevel@tonic-gate      int length;
990Sstevel@tonic-gate {
1000Sstevel@tonic-gate    if (length < (1<<7)) {
1010Sstevel@tonic-gate       *(*buf)++ = (unsigned char) length;
1020Sstevel@tonic-gate    } else {
1030Sstevel@tonic-gate       *(*buf)++ = (unsigned char) (der_length_size(length)+127);
104*5053Sgtb #if INT_MAX > 0x7fff
1050Sstevel@tonic-gate       if (length >= (1<<24))
1060Sstevel@tonic-gate 	 *(*buf)++ = (unsigned char) (length>>24);
1070Sstevel@tonic-gate       if (length >= (1<<16))
1080Sstevel@tonic-gate 	 *(*buf)++ = (unsigned char) ((length>>16)&0xff);
1090Sstevel@tonic-gate #endif
1100Sstevel@tonic-gate       if (length >= (1<<8))
1110Sstevel@tonic-gate 	 *(*buf)++ = (unsigned char) ((length>>8)&0xff);
1120Sstevel@tonic-gate       *(*buf)++ = (unsigned char) (length&0xff);
1130Sstevel@tonic-gate    }
1140Sstevel@tonic-gate }
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate /* returns decoded length, or < 0 on failure.  Advances buf and
1170Sstevel@tonic-gate    decrements bufsize */
1180Sstevel@tonic-gate 
der_read_length(buf,bufsize)1190Sstevel@tonic-gate static int der_read_length(buf, bufsize)
1200Sstevel@tonic-gate      unsigned char **buf;
1210Sstevel@tonic-gate      int *bufsize;
1220Sstevel@tonic-gate {
1230Sstevel@tonic-gate    unsigned char sf;
1240Sstevel@tonic-gate    int ret;
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate    if (*bufsize < 1)
1270Sstevel@tonic-gate       return(-1);
1280Sstevel@tonic-gate    sf = *(*buf)++;
1290Sstevel@tonic-gate    (*bufsize)--;
1300Sstevel@tonic-gate    if (sf & 0x80) {
1310Sstevel@tonic-gate       if ((sf &= 0x7f) > ((*bufsize)-1))
1320Sstevel@tonic-gate 	 return(-1);
133*5053Sgtb       if (sf > sizeof(int))
1340Sstevel@tonic-gate 	  return (-1);
1350Sstevel@tonic-gate       ret = 0;
1360Sstevel@tonic-gate       for (; sf; sf--) {
1370Sstevel@tonic-gate 	 ret = (ret<<8) + (*(*buf)++);
1380Sstevel@tonic-gate 	 (*bufsize)--;
1390Sstevel@tonic-gate       }
1400Sstevel@tonic-gate    } else {
1410Sstevel@tonic-gate       ret = sf;
1420Sstevel@tonic-gate    }
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate    return(ret);
1450Sstevel@tonic-gate }
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate /* returns the length of a token, given the mech oid and the body size */
1480Sstevel@tonic-gate 
g_token_size(mech,body_size)149*5053Sgtb unsigned int g_token_size(mech, body_size)
150*5053Sgtb      const gss_OID_desc * mech;
1510Sstevel@tonic-gate      unsigned int body_size;
1520Sstevel@tonic-gate {
1530Sstevel@tonic-gate    /* set body_size to sequence contents size */
1540Sstevel@tonic-gate    body_size += 4 + (int) mech->length;         /* NEED overflow check */
1550Sstevel@tonic-gate    return(1 + der_length_size((int) body_size) + body_size);
1560Sstevel@tonic-gate }
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate /* fills in a buffer with the token header.  The buffer is assumed to
1590Sstevel@tonic-gate    be the right size.  buf is advanced past the token header */
1600Sstevel@tonic-gate 
g_make_token_header(mech,body_size,buf,tok_type)1610Sstevel@tonic-gate void g_make_token_header(mech, body_size, buf, tok_type)
162*5053Sgtb      const gss_OID_desc * mech;
163*5053Sgtb      unsigned int body_size;
1640Sstevel@tonic-gate      unsigned char **buf;
1650Sstevel@tonic-gate      int tok_type;
1660Sstevel@tonic-gate {
1670Sstevel@tonic-gate    *(*buf)++ = 0x60;
168*5053Sgtb    der_write_length(buf,
169*5053Sgtb        (tok_type == -1) ? 2 : (int) (4 + mech->length + body_size));
1700Sstevel@tonic-gate    *(*buf)++ = 0x06;
1710Sstevel@tonic-gate    *(*buf)++ = (unsigned char) mech->length;
172*5053Sgtb    TWRITE_STR(*buf, mech->elements, mech->length);
1730Sstevel@tonic-gate    if (tok_type != -1) {
174*5053Sgtb        *(*buf)++ = (unsigned char) ((tok_type>>8)&0xff);
175*5053Sgtb        *(*buf)++ = (unsigned char) (tok_type&0xff);
1760Sstevel@tonic-gate    }
1770Sstevel@tonic-gate }
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate /*
1800Sstevel@tonic-gate  * Given a buffer containing a token, reads and verifies the token,
1810Sstevel@tonic-gate  * leaving buf advanced past the token header, and setting body_size
1820Sstevel@tonic-gate  * to the number of remaining bytes.  Returns 0 on success,
1830Sstevel@tonic-gate  * G_BAD_TOK_HEADER for a variety of errors, and G_WRONG_MECH if the
1840Sstevel@tonic-gate  * mechanism in the token does not match the mech argument.  buf and
1850Sstevel@tonic-gate  * *body_size are left unmodified on error.
1860Sstevel@tonic-gate  */
1870Sstevel@tonic-gate 
g_verify_token_header(mech,body_size,buf_in,tok_type,toksize_in,wrapper_required)1880Sstevel@tonic-gate gss_int32 g_verify_token_header(mech, body_size, buf_in, tok_type, toksize_in,
1890Sstevel@tonic-gate 				wrapper_required)
190*5053Sgtb      const gss_OID_desc * mech;
191*5053Sgtb      unsigned int *body_size;
192*5053Sgtb      unsigned char **buf_in;
193*5053Sgtb      int tok_type;
194*5053Sgtb      unsigned int toksize_in;
195*5053Sgtb      int wrapper_required;
1960Sstevel@tonic-gate {
1970Sstevel@tonic-gate    unsigned char *buf = *buf_in;
1980Sstevel@tonic-gate    int seqsize;
1990Sstevel@tonic-gate    gss_OID_desc toid;
2000Sstevel@tonic-gate    int toksize = toksize_in;
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate    if ((toksize-=1) < 0)
203*5053Sgtb       return(G_BAD_TOK_HEADER);
2040Sstevel@tonic-gate    if (*buf++ != 0x60) {
205*5053Sgtb        if (wrapper_required)
2060Sstevel@tonic-gate 	   return(G_BAD_TOK_HEADER);
207*5053Sgtb        buf--;
208*5053Sgtb        toksize++;
209*5053Sgtb        goto skip_wrapper;
2100Sstevel@tonic-gate    }
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate    if ((seqsize = der_read_length(&buf, &toksize)) < 0)
213*5053Sgtb       return(G_BAD_TOK_HEADER);
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate    if (seqsize != toksize)
216*5053Sgtb       return(G_BAD_TOK_HEADER);
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate    if ((toksize-=1) < 0)
219*5053Sgtb       return(G_BAD_TOK_HEADER);
2200Sstevel@tonic-gate    if (*buf++ != 0x06)
221*5053Sgtb       return(G_BAD_TOK_HEADER);
222*5053Sgtb 
2230Sstevel@tonic-gate    if ((toksize-=1) < 0)
224*5053Sgtb       return(G_BAD_TOK_HEADER);
2250Sstevel@tonic-gate    toid.length = *buf++;
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate    if ((toksize-=toid.length) < 0)
228*5053Sgtb       return(G_BAD_TOK_HEADER);
2290Sstevel@tonic-gate    toid.elements = buf;
2300Sstevel@tonic-gate    buf+=toid.length;
2310Sstevel@tonic-gate 
232*5053Sgtb    if (! g_OID_equal(&toid, mech))
233*5053Sgtb        return  G_WRONG_MECH;
2340Sstevel@tonic-gate skip_wrapper:
2350Sstevel@tonic-gate    if (tok_type != -1) {
236*5053Sgtb        if ((toksize-=2) < 0)
2370Sstevel@tonic-gate 	   return(G_BAD_TOK_HEADER);
2380Sstevel@tonic-gate 
239*5053Sgtb        if ((*buf++ != ((tok_type>>8)&0xff)) ||
2400Sstevel@tonic-gate 	   (*buf++ != (tok_type&0xff)))
2410Sstevel@tonic-gate 	   return(G_WRONG_TOKID);
2420Sstevel@tonic-gate    }
2430Sstevel@tonic-gate    *buf_in = buf;
2440Sstevel@tonic-gate    *body_size = toksize;
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate    return 0;
2470Sstevel@tonic-gate }
248