1ab9b2e15Sgtb /*
2ab9b2e15Sgtb  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
3ab9b2e15Sgtb  * Use is subject to license terms.
4ab9b2e15Sgtb  */
5ab9b2e15Sgtb 
67c478bd9Sstevel@tonic-gate /*
77c478bd9Sstevel@tonic-gate  * Copyright 1993 by OpenVision Technologies, Inc.
8*2d6eb4a5SToomas Soome  *
97c478bd9Sstevel@tonic-gate  * Permission to use, copy, modify, distribute, and sell this software
107c478bd9Sstevel@tonic-gate  * and its documentation for any purpose is hereby granted without fee,
117c478bd9Sstevel@tonic-gate  * provided that the above copyright notice appears in all copies and
127c478bd9Sstevel@tonic-gate  * that both that copyright notice and this permission notice appear in
137c478bd9Sstevel@tonic-gate  * supporting documentation, and that the name of OpenVision not be used
147c478bd9Sstevel@tonic-gate  * in advertising or publicity pertaining to distribution of the software
157c478bd9Sstevel@tonic-gate  * without specific, written prior permission. OpenVision makes no
167c478bd9Sstevel@tonic-gate  * representations about the suitability of this software for any
177c478bd9Sstevel@tonic-gate  * purpose.  It is provided "as is" without express or implied warranty.
18*2d6eb4a5SToomas Soome  *
197c478bd9Sstevel@tonic-gate  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
207c478bd9Sstevel@tonic-gate  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
217c478bd9Sstevel@tonic-gate  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
227c478bd9Sstevel@tonic-gate  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
237c478bd9Sstevel@tonic-gate  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
247c478bd9Sstevel@tonic-gate  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
257c478bd9Sstevel@tonic-gate  * PERFORMANCE OF THIS SOFTWARE.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
28ab9b2e15Sgtb #include "gssapiP_generic.h"
297c478bd9Sstevel@tonic-gate 
30ab9b2e15Sgtb #ifdef _KERNEL
31ab9b2e15Sgtb #include <sys/systm.h>
32ab9b2e15Sgtb #else
33ab9b2e15Sgtb #ifdef HAVE_MEMORY_H
34ab9b2e15Sgtb #include <memory.h>
35505d05c7Sgtb #endif
36ab9b2e15Sgtb #include <limits.h>
37ab9b2e15Sgtb #include <string.h>
38ab9b2e15Sgtb #endif /* _KERNEL */
39ab9b2e15Sgtb 
40505d05c7Sgtb 
417c478bd9Sstevel@tonic-gate /*
42ab9b2e15Sgtb  * $Id: util_token.c 17987 2006-05-09 11:31:02Z epeisach $
437c478bd9Sstevel@tonic-gate  */
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate /* XXXX this code currently makes the assumption that a mech oid will
467c478bd9Sstevel@tonic-gate    never be longer than 127 bytes.  This assumption is not inherent in
477c478bd9Sstevel@tonic-gate    the interfaces, so the code can be fixed if the OSI namespace
487c478bd9Sstevel@tonic-gate    balloons unexpectedly. */
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /* Each token looks like this:
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate 0x60				tag for APPLICATION 0, SEQUENCE
537c478bd9Sstevel@tonic-gate 					(constructed, definite-length)
547c478bd9Sstevel@tonic-gate 	<length>		possible multiple bytes, need to parse/generate
557c478bd9Sstevel@tonic-gate 	0x06			tag for OBJECT IDENTIFIER
567c478bd9Sstevel@tonic-gate 		<moid_length>	compile-time constant string (assume 1 byte)
577c478bd9Sstevel@tonic-gate 		<moid_bytes>	compile-time constant string
587c478bd9Sstevel@tonic-gate 	<inner_bytes>		the ANY containing the application token
597c478bd9Sstevel@tonic-gate 					bytes 0,1 are the token type
607c478bd9Sstevel@tonic-gate 					bytes 2,n are the token data
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate Note that the token type field is a feature of RFC 1964 mechanisms and
63ab9b2e15Sgtb is not used by other GSSAPI mechanisms.  As such, a token type of -1
647c478bd9Sstevel@tonic-gate is interpreted to mean that no token type should be expected or
65*2d6eb4a5SToomas Soome generated.
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate For the purposes of this abstraction, the token "header" consists of
687c478bd9Sstevel@tonic-gate the sequence tag and length octets, the mech OID DER encoding, and the
697c478bd9Sstevel@tonic-gate first two inner bytes, which indicate the token type.  The token
707c478bd9Sstevel@tonic-gate "body" consists of everything else.
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate */
737c478bd9Sstevel@tonic-gate 
der_length_size(length)74ab9b2e15Sgtb static unsigned int der_length_size(length)
757c478bd9Sstevel@tonic-gate      int length;
767c478bd9Sstevel@tonic-gate {
777c478bd9Sstevel@tonic-gate    if (length < (1<<7))
787c478bd9Sstevel@tonic-gate       return(1);
797c478bd9Sstevel@tonic-gate    else if (length < (1<<8))
807c478bd9Sstevel@tonic-gate       return(2);
81ab9b2e15Sgtb #if INT_MAX == 0x7fff
827c478bd9Sstevel@tonic-gate    else
837c478bd9Sstevel@tonic-gate        return(3);
847c478bd9Sstevel@tonic-gate #else
857c478bd9Sstevel@tonic-gate    else if (length < (1<<16))
867c478bd9Sstevel@tonic-gate       return(3);
877c478bd9Sstevel@tonic-gate    else if (length < (1<<24))
887c478bd9Sstevel@tonic-gate       return(4);
897c478bd9Sstevel@tonic-gate    else
907c478bd9Sstevel@tonic-gate       return(5);
917c478bd9Sstevel@tonic-gate #endif
927c478bd9Sstevel@tonic-gate }
937c478bd9Sstevel@tonic-gate 
der_write_length(buf,length)947c478bd9Sstevel@tonic-gate static void der_write_length(buf, length)
957c478bd9Sstevel@tonic-gate      unsigned char **buf;
967c478bd9Sstevel@tonic-gate      int length;
977c478bd9Sstevel@tonic-gate {
987c478bd9Sstevel@tonic-gate    if (length < (1<<7)) {
997c478bd9Sstevel@tonic-gate       *(*buf)++ = (unsigned char) length;
1007c478bd9Sstevel@tonic-gate    } else {
1017c478bd9Sstevel@tonic-gate       *(*buf)++ = (unsigned char) (der_length_size(length)+127);
102ab9b2e15Sgtb #if INT_MAX > 0x7fff
1037c478bd9Sstevel@tonic-gate       if (length >= (1<<24))
1047c478bd9Sstevel@tonic-gate 	 *(*buf)++ = (unsigned char) (length>>24);
1057c478bd9Sstevel@tonic-gate       if (length >= (1<<16))
1067c478bd9Sstevel@tonic-gate 	 *(*buf)++ = (unsigned char) ((length>>16)&0xff);
1077c478bd9Sstevel@tonic-gate #endif
1087c478bd9Sstevel@tonic-gate       if (length >= (1<<8))
1097c478bd9Sstevel@tonic-gate 	 *(*buf)++ = (unsigned char) ((length>>8)&0xff);
1107c478bd9Sstevel@tonic-gate       *(*buf)++ = (unsigned char) (length&0xff);
1117c478bd9Sstevel@tonic-gate    }
1127c478bd9Sstevel@tonic-gate }
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate /* returns decoded length, or < 0 on failure.  Advances buf and
1157c478bd9Sstevel@tonic-gate    decrements bufsize */
1167c478bd9Sstevel@tonic-gate 
der_read_length(buf,bufsize)1177c478bd9Sstevel@tonic-gate static int der_read_length(buf, bufsize)
1187c478bd9Sstevel@tonic-gate      unsigned char **buf;
1197c478bd9Sstevel@tonic-gate      int *bufsize;
1207c478bd9Sstevel@tonic-gate {
1217c478bd9Sstevel@tonic-gate    unsigned char sf;
1227c478bd9Sstevel@tonic-gate    int ret;
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate    if (*bufsize < 1)
1257c478bd9Sstevel@tonic-gate       return(-1);
1267c478bd9Sstevel@tonic-gate    sf = *(*buf)++;
1277c478bd9Sstevel@tonic-gate    (*bufsize)--;
1287c478bd9Sstevel@tonic-gate    if (sf & 0x80) {
1297c478bd9Sstevel@tonic-gate       if ((sf &= 0x7f) > ((*bufsize)-1))
1307c478bd9Sstevel@tonic-gate 	 return(-1);
131ab9b2e15Sgtb       if (sf > sizeof(int))
1327c478bd9Sstevel@tonic-gate 	  return (-1);
1337c478bd9Sstevel@tonic-gate       ret = 0;
1347c478bd9Sstevel@tonic-gate       for (; sf; sf--) {
1357c478bd9Sstevel@tonic-gate 	 ret = (ret<<8) + (*(*buf)++);
1367c478bd9Sstevel@tonic-gate 	 (*bufsize)--;
1377c478bd9Sstevel@tonic-gate       }
1387c478bd9Sstevel@tonic-gate    } else {
1397c478bd9Sstevel@tonic-gate       ret = sf;
1407c478bd9Sstevel@tonic-gate    }
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate    return(ret);
1437c478bd9Sstevel@tonic-gate }
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate /* returns the length of a token, given the mech oid and the body size */
1467c478bd9Sstevel@tonic-gate 
g_token_size(mech,body_size)147ab9b2e15Sgtb unsigned int g_token_size(mech, body_size)
148ab9b2e15Sgtb      const gss_OID_desc * mech;
1497c478bd9Sstevel@tonic-gate      unsigned int body_size;
1507c478bd9Sstevel@tonic-gate {
1517c478bd9Sstevel@tonic-gate    /* set body_size to sequence contents size */
1527c478bd9Sstevel@tonic-gate    body_size += 4 + (int) mech->length;         /* NEED overflow check */
1537c478bd9Sstevel@tonic-gate    return(1 + der_length_size((int) body_size) + body_size);
1547c478bd9Sstevel@tonic-gate }
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate /* fills in a buffer with the token header.  The buffer is assumed to
1577c478bd9Sstevel@tonic-gate    be the right size.  buf is advanced past the token header */
1587c478bd9Sstevel@tonic-gate 
g_make_token_header(mech,body_size,buf,tok_type)1597c478bd9Sstevel@tonic-gate void g_make_token_header(mech, body_size, buf, tok_type)
160ab9b2e15Sgtb      const gss_OID_desc * mech;
161ab9b2e15Sgtb      unsigned int body_size;
1627c478bd9Sstevel@tonic-gate      unsigned char **buf;
1637c478bd9Sstevel@tonic-gate      int tok_type;
1647c478bd9Sstevel@tonic-gate {
1657c478bd9Sstevel@tonic-gate    *(*buf)++ = 0x60;
166ab9b2e15Sgtb    der_write_length(buf,
167ab9b2e15Sgtb        (tok_type == -1) ? 2 : (int) (4 + mech->length + body_size));
1687c478bd9Sstevel@tonic-gate    *(*buf)++ = 0x06;
1697c478bd9Sstevel@tonic-gate    *(*buf)++ = (unsigned char) mech->length;
170ab9b2e15Sgtb    TWRITE_STR(*buf, mech->elements, mech->length);
1717c478bd9Sstevel@tonic-gate    if (tok_type != -1) {
172ab9b2e15Sgtb        *(*buf)++ = (unsigned char) ((tok_type>>8)&0xff);
173ab9b2e15Sgtb        *(*buf)++ = (unsigned char) (tok_type&0xff);
1747c478bd9Sstevel@tonic-gate    }
1757c478bd9Sstevel@tonic-gate }
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate /*
1787c478bd9Sstevel@tonic-gate  * Given a buffer containing a token, reads and verifies the token,
1797c478bd9Sstevel@tonic-gate  * leaving buf advanced past the token header, and setting body_size
1807c478bd9Sstevel@tonic-gate  * to the number of remaining bytes.  Returns 0 on success,
1817c478bd9Sstevel@tonic-gate  * G_BAD_TOK_HEADER for a variety of errors, and G_WRONG_MECH if the
1827c478bd9Sstevel@tonic-gate  * mechanism in the token does not match the mech argument.  buf and
1837c478bd9Sstevel@tonic-gate  * *body_size are left unmodified on error.
1847c478bd9Sstevel@tonic-gate  */
1857c478bd9Sstevel@tonic-gate 
g_verify_token_header(mech,body_size,buf_in,tok_type,toksize_in,wrapper_required)1867c478bd9Sstevel@tonic-gate gss_int32 g_verify_token_header(mech, body_size, buf_in, tok_type, toksize_in,
1877c478bd9Sstevel@tonic-gate 				wrapper_required)
188ab9b2e15Sgtb      const gss_OID_desc * mech;
189ab9b2e15Sgtb      unsigned int *body_size;
190ab9b2e15Sgtb      unsigned char **buf_in;
191ab9b2e15Sgtb      int tok_type;
192ab9b2e15Sgtb      unsigned int toksize_in;
193ab9b2e15Sgtb      int wrapper_required;
1947c478bd9Sstevel@tonic-gate {
1957c478bd9Sstevel@tonic-gate    unsigned char *buf = *buf_in;
1967c478bd9Sstevel@tonic-gate    int seqsize;
1977c478bd9Sstevel@tonic-gate    gss_OID_desc toid;
1987c478bd9Sstevel@tonic-gate    int toksize = toksize_in;
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate    if ((toksize-=1) < 0)
201ab9b2e15Sgtb       return(G_BAD_TOK_HEADER);
2027c478bd9Sstevel@tonic-gate    if (*buf++ != 0x60) {
203ab9b2e15Sgtb        if (wrapper_required)
2047c478bd9Sstevel@tonic-gate 	   return(G_BAD_TOK_HEADER);
205ab9b2e15Sgtb        buf--;
206ab9b2e15Sgtb        toksize++;
207ab9b2e15Sgtb        goto skip_wrapper;
2087c478bd9Sstevel@tonic-gate    }
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate    if ((seqsize = der_read_length(&buf, &toksize)) < 0)
211ab9b2e15Sgtb       return(G_BAD_TOK_HEADER);
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate    if (seqsize != toksize)
214ab9b2e15Sgtb       return(G_BAD_TOK_HEADER);
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate    if ((toksize-=1) < 0)
217ab9b2e15Sgtb       return(G_BAD_TOK_HEADER);
2187c478bd9Sstevel@tonic-gate    if (*buf++ != 0x06)
219ab9b2e15Sgtb       return(G_BAD_TOK_HEADER);
220*2d6eb4a5SToomas Soome 
2217c478bd9Sstevel@tonic-gate    if ((toksize-=1) < 0)
222ab9b2e15Sgtb       return(G_BAD_TOK_HEADER);
2237c478bd9Sstevel@tonic-gate    toid.length = *buf++;
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate    if ((toksize-=toid.length) < 0)
226ab9b2e15Sgtb       return(G_BAD_TOK_HEADER);
2277c478bd9Sstevel@tonic-gate    toid.elements = buf;
2287c478bd9Sstevel@tonic-gate    buf+=toid.length;
2297c478bd9Sstevel@tonic-gate 
230*2d6eb4a5SToomas Soome    if (! g_OID_equal(&toid, mech))
231ab9b2e15Sgtb        return  G_WRONG_MECH;
2327c478bd9Sstevel@tonic-gate skip_wrapper:
2337c478bd9Sstevel@tonic-gate    if (tok_type != -1) {
234ab9b2e15Sgtb        if ((toksize-=2) < 0)
2357c478bd9Sstevel@tonic-gate 	   return(G_BAD_TOK_HEADER);
2367c478bd9Sstevel@tonic-gate 
237ab9b2e15Sgtb        if ((*buf++ != ((tok_type>>8)&0xff)) ||
2387c478bd9Sstevel@tonic-gate 	   (*buf++ != (tok_type&0xff)))
2397c478bd9Sstevel@tonic-gate 	   return(G_WRONG_TOKID);
2407c478bd9Sstevel@tonic-gate    }
2417c478bd9Sstevel@tonic-gate    *buf_in = buf;
2427c478bd9Sstevel@tonic-gate    *body_size = toksize;
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate    return 0;
2457c478bd9Sstevel@tonic-gate }
246