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 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 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 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 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 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 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 if (!ret) { 2261da177e4SLinus Torvalds *buf_in = buf; 2271da177e4SLinus Torvalds *body_size = toksize; 2281da177e4SLinus Torvalds } 2291da177e4SLinus Torvalds 230a02cec21SEric Dumazet return ret; 2311da177e4SLinus Torvalds } 2321da177e4SLinus Torvalds 2337bd88269STrond Myklebust EXPORT_SYMBOL_GPL(g_verify_token_header); 2341da177e4SLinus Torvalds 235