11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  linux/net/sunrpc/gss_generic_token.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *  Adapted from MIT Kerberos 5-1.2.1 lib/gssapi/generic/util_token.c
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  *  Copyright (c) 2000 The Regents of the University of Michigan.
71da177e4SLinus Torvalds  *  All rights reserved.
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  *  Andy Adamson   <andros@umich.edu>
101da177e4SLinus Torvalds  */
111da177e4SLinus Torvalds 
121da177e4SLinus Torvalds /*
131da177e4SLinus Torvalds  * Copyright 1993 by OpenVision Technologies, Inc.
141da177e4SLinus Torvalds  *
151da177e4SLinus Torvalds  * Permission to use, copy, modify, distribute, and sell this software
161da177e4SLinus Torvalds  * and its documentation for any purpose is hereby granted without fee,
171da177e4SLinus Torvalds  * provided that the above copyright notice appears in all copies and
181da177e4SLinus Torvalds  * that both that copyright notice and this permission notice appear in
191da177e4SLinus Torvalds  * supporting documentation, and that the name of OpenVision not be used
201da177e4SLinus Torvalds  * in advertising or publicity pertaining to distribution of the software
211da177e4SLinus Torvalds  * without specific, written prior permission. OpenVision makes no
221da177e4SLinus Torvalds  * representations about the suitability of this software for any
231da177e4SLinus Torvalds  * purpose.  It is provided "as is" without express or implied warranty.
241da177e4SLinus Torvalds  *
251da177e4SLinus Torvalds  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
261da177e4SLinus Torvalds  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
271da177e4SLinus Torvalds  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
281da177e4SLinus Torvalds  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
291da177e4SLinus Torvalds  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
301da177e4SLinus Torvalds  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
311da177e4SLinus Torvalds  * PERFORMANCE OF THIS SOFTWARE.
321da177e4SLinus Torvalds  */
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds #include <linux/types.h>
351da177e4SLinus Torvalds #include <linux/module.h>
361da177e4SLinus Torvalds #include <linux/string.h>
371da177e4SLinus Torvalds #include <linux/sunrpc/sched.h>
381da177e4SLinus Torvalds #include <linux/sunrpc/gss_asn1.h>
391da177e4SLinus Torvalds 
401da177e4SLinus Torvalds 
41f895b252SJeff Layton #if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
421da177e4SLinus Torvalds # define RPCDBG_FACILITY        RPCDBG_AUTH
431da177e4SLinus Torvalds #endif
441da177e4SLinus Torvalds 
451da177e4SLinus Torvalds 
461da177e4SLinus Torvalds /* TWRITE_STR from gssapiP_generic.h */
471da177e4SLinus Torvalds #define TWRITE_STR(ptr, str, len) \
481da177e4SLinus Torvalds 	memcpy((ptr), (char *) (str), (len)); \
491da177e4SLinus Torvalds 	(ptr) += (len);
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds /* XXXX this code currently makes the assumption that a mech oid will
521da177e4SLinus Torvalds    never be longer than 127 bytes.  This assumption is not inherent in
531da177e4SLinus Torvalds    the interfaces, so the code can be fixed if the OSI namespace
541da177e4SLinus Torvalds    balloons unexpectedly. */
551da177e4SLinus Torvalds 
561da177e4SLinus Torvalds /* Each token looks like this:
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds 0x60				tag for APPLICATION 0, SEQUENCE
591da177e4SLinus Torvalds 					(constructed, definite-length)
601da177e4SLinus Torvalds 	<length>		possible multiple bytes, need to parse/generate
611da177e4SLinus Torvalds 	0x06			tag for OBJECT IDENTIFIER
621da177e4SLinus Torvalds 		<moid_length>	compile-time constant string (assume 1 byte)
631da177e4SLinus Torvalds 		<moid_bytes>	compile-time constant string
641da177e4SLinus Torvalds 	<inner_bytes>		the ANY containing the application token
651da177e4SLinus Torvalds 					bytes 0,1 are the token type
661da177e4SLinus Torvalds 					bytes 2,n are the token data
671da177e4SLinus Torvalds 
681da177e4SLinus Torvalds For the purposes of this abstraction, the token "header" consists of
691da177e4SLinus Torvalds the sequence tag and length octets, the mech OID DER encoding, and the
701da177e4SLinus Torvalds first two inner bytes, which indicate the token type.  The token
711da177e4SLinus Torvalds "body" consists of everything else.
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds */
741da177e4SLinus Torvalds 
751da177e4SLinus Torvalds static int
der_length_size(int length)761da177e4SLinus Torvalds der_length_size( int length)
771da177e4SLinus Torvalds {
781da177e4SLinus Torvalds 	if (length < (1<<7))
79a02cec21SEric Dumazet 		return 1;
801da177e4SLinus Torvalds 	else if (length < (1<<8))
81a02cec21SEric Dumazet 		return 2;
821da177e4SLinus Torvalds #if (SIZEOF_INT == 2)
831da177e4SLinus Torvalds 	else
84a02cec21SEric Dumazet 		return 3;
851da177e4SLinus Torvalds #else
861da177e4SLinus Torvalds 	else if (length < (1<<16))
87a02cec21SEric Dumazet 		return 3;
881da177e4SLinus Torvalds 	else if (length < (1<<24))
89a02cec21SEric Dumazet 		return 4;
901da177e4SLinus Torvalds 	else
91a02cec21SEric Dumazet 		return 5;
921da177e4SLinus Torvalds #endif
931da177e4SLinus Torvalds }
941da177e4SLinus Torvalds 
951da177e4SLinus Torvalds static void
der_write_length(unsigned char ** buf,int length)961da177e4SLinus Torvalds der_write_length(unsigned char **buf, int length)
971da177e4SLinus Torvalds {
981da177e4SLinus Torvalds 	if (length < (1<<7)) {
991da177e4SLinus Torvalds 		*(*buf)++ = (unsigned char) length;
1001da177e4SLinus Torvalds 	} else {
1011da177e4SLinus Torvalds 		*(*buf)++ = (unsigned char) (der_length_size(length)+127);
1021da177e4SLinus Torvalds #if (SIZEOF_INT > 2)
1031da177e4SLinus Torvalds 		if (length >= (1<<24))
1041da177e4SLinus Torvalds 			*(*buf)++ = (unsigned char) (length>>24);
1051da177e4SLinus Torvalds 		if (length >= (1<<16))
1061da177e4SLinus Torvalds 			*(*buf)++ = (unsigned char) ((length>>16)&0xff);
1071da177e4SLinus Torvalds #endif
1081da177e4SLinus Torvalds 		if (length >= (1<<8))
1091da177e4SLinus Torvalds 			*(*buf)++ = (unsigned char) ((length>>8)&0xff);
1101da177e4SLinus Torvalds 		*(*buf)++ = (unsigned char) (length&0xff);
1111da177e4SLinus Torvalds 	}
1121da177e4SLinus Torvalds }
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds /* returns decoded length, or < 0 on failure.  Advances buf and
1151da177e4SLinus Torvalds    decrements bufsize */
1161da177e4SLinus Torvalds 
1171da177e4SLinus Torvalds static int
der_read_length(unsigned char ** buf,int * bufsize)1181da177e4SLinus Torvalds der_read_length(unsigned char **buf, int *bufsize)
1191da177e4SLinus Torvalds {
1201da177e4SLinus Torvalds 	unsigned char sf;
1211da177e4SLinus Torvalds 	int ret;
1221da177e4SLinus Torvalds 
1231da177e4SLinus Torvalds 	if (*bufsize < 1)
124a02cec21SEric Dumazet 		return -1;
1251da177e4SLinus Torvalds 	sf = *(*buf)++;
1261da177e4SLinus Torvalds 	(*bufsize)--;
1271da177e4SLinus Torvalds 	if (sf & 0x80) {
1281da177e4SLinus Torvalds 		if ((sf &= 0x7f) > ((*bufsize)-1))
129a02cec21SEric Dumazet 			return -1;
1301da177e4SLinus Torvalds 		if (sf > SIZEOF_INT)
131a02cec21SEric Dumazet 			return -1;
1321da177e4SLinus Torvalds 		ret = 0;
1331da177e4SLinus Torvalds 		for (; sf; sf--) {
1341da177e4SLinus Torvalds 			ret = (ret<<8) + (*(*buf)++);
1351da177e4SLinus Torvalds 			(*bufsize)--;
1361da177e4SLinus Torvalds 		}
1371da177e4SLinus Torvalds 	} else {
1381da177e4SLinus Torvalds 		ret = sf;
1391da177e4SLinus Torvalds 	}
1401da177e4SLinus Torvalds 
141a02cec21SEric Dumazet 	return ret;
1421da177e4SLinus Torvalds }
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds /* returns the length of a token, given the mech oid and the body size */
1451da177e4SLinus Torvalds 
1461da177e4SLinus Torvalds int
g_token_size(struct xdr_netobj * mech,unsigned int body_size)1471da177e4SLinus Torvalds g_token_size(struct xdr_netobj *mech, unsigned int body_size)
1481da177e4SLinus Torvalds {
1491da177e4SLinus Torvalds 	/* set body_size to sequence contents size */
1504ab4b0beSKevin Coffman 	body_size += 2 + (int) mech->len;         /* NEED overflow check */
151a02cec21SEric Dumazet 	return 1 + der_length_size(body_size) + body_size;
1521da177e4SLinus Torvalds }
1531da177e4SLinus Torvalds 
1547bd88269STrond Myklebust EXPORT_SYMBOL_GPL(g_token_size);
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds /* fills in a buffer with the token header.  The buffer is assumed to
1571da177e4SLinus Torvalds    be the right size.  buf is advanced past the token header */
1581da177e4SLinus Torvalds 
1591da177e4SLinus Torvalds void
g_make_token_header(struct xdr_netobj * mech,int body_size,unsigned char ** buf)1601da177e4SLinus Torvalds g_make_token_header(struct xdr_netobj *mech, int body_size, unsigned char **buf)
1611da177e4SLinus Torvalds {
1621da177e4SLinus Torvalds 	*(*buf)++ = 0x60;
1634ab4b0beSKevin Coffman 	der_write_length(buf, 2 + mech->len + body_size);
1641da177e4SLinus Torvalds 	*(*buf)++ = 0x06;
1651da177e4SLinus Torvalds 	*(*buf)++ = (unsigned char) mech->len;
1661da177e4SLinus Torvalds 	TWRITE_STR(*buf, mech->data, ((int) mech->len));
1671da177e4SLinus Torvalds }
1681da177e4SLinus Torvalds 
1697bd88269STrond Myklebust EXPORT_SYMBOL_GPL(g_make_token_header);
1701da177e4SLinus Torvalds 
1711da177e4SLinus Torvalds /*
1721da177e4SLinus Torvalds  * Given a buffer containing a token, reads and verifies the token,
1731da177e4SLinus Torvalds  * leaving buf advanced past the token header, and setting body_size
1741da177e4SLinus Torvalds  * to the number of remaining bytes.  Returns 0 on success,
1751da177e4SLinus Torvalds  * G_BAD_TOK_HEADER for a variety of errors, and G_WRONG_MECH if the
1761da177e4SLinus Torvalds  * mechanism in the token does not match the mech argument.  buf and
1771da177e4SLinus Torvalds  * *body_size are left unmodified on error.
1781da177e4SLinus Torvalds  */
1791da177e4SLinus Torvalds u32
g_verify_token_header(struct xdr_netobj * mech,int * body_size,unsigned char ** buf_in,int toksize)1801da177e4SLinus Torvalds g_verify_token_header(struct xdr_netobj *mech, int *body_size,
1811da177e4SLinus Torvalds 		      unsigned char **buf_in, int toksize)
1821da177e4SLinus Torvalds {
1831da177e4SLinus Torvalds 	unsigned char *buf = *buf_in;
1841da177e4SLinus Torvalds 	int seqsize;
1851da177e4SLinus Torvalds 	struct xdr_netobj toid;
1861da177e4SLinus Torvalds 	int ret = 0;
1871da177e4SLinus Torvalds 
1881da177e4SLinus Torvalds 	if ((toksize-=1) < 0)
189a02cec21SEric Dumazet 		return G_BAD_TOK_HEADER;
1901da177e4SLinus Torvalds 	if (*buf++ != 0x60)
191a02cec21SEric Dumazet 		return G_BAD_TOK_HEADER;
1921da177e4SLinus Torvalds 
1931da177e4SLinus Torvalds 	if ((seqsize = der_read_length(&buf, &toksize)) < 0)
194a02cec21SEric Dumazet 		return G_BAD_TOK_HEADER;
1951da177e4SLinus Torvalds 
1961da177e4SLinus Torvalds 	if (seqsize != toksize)
197a02cec21SEric Dumazet 		return G_BAD_TOK_HEADER;
1981da177e4SLinus Torvalds 
1991da177e4SLinus Torvalds 	if ((toksize-=1) < 0)
200a02cec21SEric Dumazet 		return G_BAD_TOK_HEADER;
2011da177e4SLinus Torvalds 	if (*buf++ != 0x06)
202a02cec21SEric Dumazet 		return G_BAD_TOK_HEADER;
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds 	if ((toksize-=1) < 0)
205a02cec21SEric Dumazet 		return G_BAD_TOK_HEADER;
2061da177e4SLinus Torvalds 	toid.len = *buf++;
2071da177e4SLinus Torvalds 
2081da177e4SLinus Torvalds 	if ((toksize-=toid.len) < 0)
209a02cec21SEric Dumazet 		return G_BAD_TOK_HEADER;
2101da177e4SLinus Torvalds 	toid.data = buf;
2111da177e4SLinus Torvalds 	buf+=toid.len;
2121da177e4SLinus Torvalds 
2131da177e4SLinus Torvalds 	if (! g_OID_equal(&toid, mech))
2141da177e4SLinus Torvalds 		ret = G_WRONG_MECH;
2151da177e4SLinus Torvalds 
2161da177e4SLinus Torvalds    /* G_WRONG_MECH is not returned immediately because it's more important
2171da177e4SLinus Torvalds       to return G_BAD_TOK_HEADER if the token header is in fact bad */
2181da177e4SLinus Torvalds 
2191da177e4SLinus Torvalds 	if ((toksize-=2) < 0)
220a02cec21SEric Dumazet 		return G_BAD_TOK_HEADER;
2211da177e4SLinus Torvalds 
2221da177e4SLinus Torvalds 	if (ret)
223a02cec21SEric Dumazet 		return ret;
2241da177e4SLinus Torvalds 
2251da177e4SLinus Torvalds 	*buf_in = buf;
2261da177e4SLinus Torvalds 	*body_size = toksize;
2271da177e4SLinus Torvalds 
228a02cec21SEric Dumazet 	return ret;
2291da177e4SLinus Torvalds }
2301da177e4SLinus Torvalds 
2317bd88269STrond Myklebust EXPORT_SYMBOL_GPL(g_verify_token_header);
232