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