Branch data Line data Source code
1 : : /* 2 : : * linux/net/sunrpc/gss_generic_token.c 3 : : * 4 : : * Adapted from MIT Kerberos 5-1.2.1 lib/gssapi/generic/util_token.c 5 : : * 6 : : * Copyright (c) 2000 The Regents of the University of Michigan. 7 : : * All rights reserved. 8 : : * 9 : : * Andy Adamson <andros@umich.edu> 10 : : */ 11 : : 12 : : /* 13 : : * Copyright 1993 by OpenVision Technologies, Inc. 14 : : * 15 : : * Permission to use, copy, modify, distribute, and sell this software 16 : : * and its documentation for any purpose is hereby granted without fee, 17 : : * provided that the above copyright notice appears in all copies and 18 : : * that both that copyright notice and this permission notice appear in 19 : : * supporting documentation, and that the name of OpenVision not be used 20 : : * in advertising or publicity pertaining to distribution of the software 21 : : * without specific, written prior permission. OpenVision makes no 22 : : * representations about the suitability of this software for any 23 : : * purpose. It is provided "as is" without express or implied warranty. 24 : : * 25 : : * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 26 : : * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 27 : : * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR 28 : : * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 29 : : * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 30 : : * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 31 : : * PERFORMANCE OF THIS SOFTWARE. 32 : : */ 33 : : 34 : : #include <linux/types.h> 35 : : #include <linux/module.h> 36 : : #include <linux/string.h> 37 : : #include <linux/sunrpc/sched.h> 38 : : #include <linux/sunrpc/gss_asn1.h> 39 : : 40 : : 41 : : #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) 42 : : # define RPCDBG_FACILITY RPCDBG_AUTH 43 : : #endif 44 : : 45 : : 46 : : /* TWRITE_STR from gssapiP_generic.h */ 47 : : #define TWRITE_STR(ptr, str, len) \ 48 : : memcpy((ptr), (char *) (str), (len)); \ 49 : : (ptr) += (len); 50 : : 51 : : /* XXXX this code currently makes the assumption that a mech oid will 52 : : never be longer than 127 bytes. This assumption is not inherent in 53 : : the interfaces, so the code can be fixed if the OSI namespace 54 : : balloons unexpectedly. */ 55 : : 56 : : /* Each token looks like this: 57 : : 58 : : 0x60 tag for APPLICATION 0, SEQUENCE 59 : : (constructed, definite-length) 60 : : <length> possible multiple bytes, need to parse/generate 61 : : 0x06 tag for OBJECT IDENTIFIER 62 : : <moid_length> compile-time constant string (assume 1 byte) 63 : : <moid_bytes> compile-time constant string 64 : : <inner_bytes> the ANY containing the application token 65 : : bytes 0,1 are the token type 66 : : bytes 2,n are the token data 67 : : 68 : : For the purposes of this abstraction, the token "header" consists of 69 : : the sequence tag and length octets, the mech OID DER encoding, and the 70 : : first two inner bytes, which indicate the token type. The token 71 : : "body" consists of everything else. 72 : : 73 : : */ 74 : : 75 : : static int 76 : : der_length_size( int length) 77 : : { 78 : 0 : if (length < (1<<7)) 79 : : return 1; 80 : 0 : else if (length < (1<<8)) 81 : : return 2; 82 : : #if (SIZEOF_INT == 2) 83 : : else 84 : : return 3; 85 : : #else 86 : 0 : else if (length < (1<<16)) 87 : : return 3; 88 : 0 : else if (length < (1<<24)) 89 : : return 4; 90 : : else 91 : : return 5; 92 : : #endif 93 : : } 94 : : 95 : : static void 96 : 0 : der_write_length(unsigned char **buf, int length) 97 : : { 98 : 0 : if (length < (1<<7)) { 99 : 0 : *(*buf)++ = (unsigned char) length; 100 : : } else { 101 : 0 : *(*buf)++ = (unsigned char) (der_length_size(length)+127); 102 : : #if (SIZEOF_INT > 2) 103 : 0 : if (length >= (1<<24)) 104 : 0 : *(*buf)++ = (unsigned char) (length>>24); 105 : 0 : if (length >= (1<<16)) 106 : 0 : *(*buf)++ = (unsigned char) ((length>>16)&0xff); 107 : : #endif 108 : 0 : if (length >= (1<<8)) 109 : 0 : *(*buf)++ = (unsigned char) ((length>>8)&0xff); 110 : 0 : *(*buf)++ = (unsigned char) (length&0xff); 111 : : } 112 : 0 : } 113 : : 114 : : /* returns decoded length, or < 0 on failure. Advances buf and 115 : : decrements bufsize */ 116 : : 117 : : static int 118 : 0 : der_read_length(unsigned char **buf, int *bufsize) 119 : : { 120 : : unsigned char sf; 121 : : int ret; 122 : : 123 : 0 : if (*bufsize < 1) 124 : : return -1; 125 : 0 : sf = *(*buf)++; 126 : 0 : (*bufsize)--; 127 : 0 : if (sf & 0x80) { 128 : 0 : if ((sf &= 0x7f) > ((*bufsize)-1)) 129 : : return -1; 130 : 0 : if (sf > SIZEOF_INT) 131 : : return -1; 132 : : ret = 0; 133 : 0 : for (; sf; sf--) { 134 : 0 : ret = (ret<<8) + (*(*buf)++); 135 : 0 : (*bufsize)--; 136 : : } 137 : : } else { 138 : 0 : ret = sf; 139 : : } 140 : : 141 : 0 : return ret; 142 : : } 143 : : 144 : : /* returns the length of a token, given the mech oid and the body size */ 145 : : 146 : : int 147 : 0 : g_token_size(struct xdr_netobj *mech, unsigned int body_size) 148 : : { 149 : : /* set body_size to sequence contents size */ 150 : 0 : body_size += 2 + (int) mech->len; /* NEED overflow check */ 151 : 0 : return 1 + der_length_size(body_size) + body_size; 152 : : } 153 : : 154 : : EXPORT_SYMBOL_GPL(g_token_size); 155 : : 156 : : /* fills in a buffer with the token header. The buffer is assumed to 157 : : be the right size. buf is advanced past the token header */ 158 : : 159 : : void 160 : 0 : g_make_token_header(struct xdr_netobj *mech, int body_size, unsigned char **buf) 161 : : { 162 : 0 : *(*buf)++ = 0x60; 163 : 0 : der_write_length(buf, 2 + mech->len + body_size); 164 : 0 : *(*buf)++ = 0x06; 165 : 0 : *(*buf)++ = (unsigned char) mech->len; 166 : 0 : TWRITE_STR(*buf, mech->data, ((int) mech->len)); 167 : 0 : } 168 : : 169 : : EXPORT_SYMBOL_GPL(g_make_token_header); 170 : : 171 : : /* 172 : : * Given a buffer containing a token, reads and verifies the token, 173 : : * leaving buf advanced past the token header, and setting body_size 174 : : * to the number of remaining bytes. Returns 0 on success, 175 : : * G_BAD_TOK_HEADER for a variety of errors, and G_WRONG_MECH if the 176 : : * mechanism in the token does not match the mech argument. buf and 177 : : * *body_size are left unmodified on error. 178 : : */ 179 : : u32 180 : 0 : g_verify_token_header(struct xdr_netobj *mech, int *body_size, 181 : : unsigned char **buf_in, int toksize) 182 : : { 183 : 0 : unsigned char *buf = *buf_in; 184 : : int seqsize; 185 : : struct xdr_netobj toid; 186 : : int ret = 0; 187 : : 188 : 0 : if ((toksize-=1) < 0) 189 : : return G_BAD_TOK_HEADER; 190 : 0 : if (*buf++ != 0x60) 191 : : return G_BAD_TOK_HEADER; 192 : : 193 : 0 : if ((seqsize = der_read_length(&buf, &toksize)) < 0) 194 : : return G_BAD_TOK_HEADER; 195 : : 196 : 0 : if (seqsize != toksize) 197 : : return G_BAD_TOK_HEADER; 198 : : 199 : 0 : if ((toksize-=1) < 0) 200 : : return G_BAD_TOK_HEADER; 201 : 0 : if (*buf++ != 0x06) 202 : : return G_BAD_TOK_HEADER; 203 : : 204 : 0 : if ((toksize-=1) < 0) 205 : : return G_BAD_TOK_HEADER; 206 : 0 : toid.len = *buf++; 207 : : 208 : 0 : if ((toksize-=toid.len) < 0) 209 : : return G_BAD_TOK_HEADER; 210 : : toid.data = buf; 211 : 0 : buf+=toid.len; 212 : : 213 : 0 : if (! g_OID_equal(&toid, mech)) 214 : : ret = G_WRONG_MECH; 215 : : 216 : : /* G_WRONG_MECH is not returned immediately because it's more important 217 : : to return G_BAD_TOK_HEADER if the token header is in fact bad */ 218 : : 219 : 0 : if ((toksize-=2) < 0) 220 : : return G_BAD_TOK_HEADER; 221 : : 222 : 0 : if (ret) 223 : 0 : return ret; 224 : : 225 : 0 : if (!ret) { 226 : 0 : *buf_in = buf; 227 : 0 : *body_size = toksize; 228 : : } 229 : : 230 : 0 : return ret; 231 : : } 232 : : 233 : : EXPORT_SYMBOL_GPL(g_verify_token_header);