linux/net/sunrpc/auth_gss/gss_generic_token.c
<<
>>
Prefs
   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/slab.h>
  37#include <linux/string.h>
  38#include <linux/sunrpc/sched.h>
  39#include <linux/sunrpc/gss_asn1.h>
  40
  41
  42#ifdef RPC_DEBUG
  43# define RPCDBG_FACILITY        RPCDBG_AUTH
  44#endif
  45
  46
  47/* TWRITE_STR from gssapiP_generic.h */
  48#define TWRITE_STR(ptr, str, len) \
  49        memcpy((ptr), (char *) (str), (len)); \
  50        (ptr) += (len);
  51
  52/* XXXX this code currently makes the assumption that a mech oid will
  53   never be longer than 127 bytes.  This assumption is not inherent in
  54   the interfaces, so the code can be fixed if the OSI namespace
  55   balloons unexpectedly. */
  56
  57/* Each token looks like this:
  58
  590x60                            tag for APPLICATION 0, SEQUENCE
  60                                        (constructed, definite-length)
  61        <length>                possible multiple bytes, need to parse/generate
  62        0x06                    tag for OBJECT IDENTIFIER
  63                <moid_length>   compile-time constant string (assume 1 byte)
  64                <moid_bytes>    compile-time constant string
  65        <inner_bytes>           the ANY containing the application token
  66                                        bytes 0,1 are the token type
  67                                        bytes 2,n are the token data
  68
  69For the purposes of this abstraction, the token "header" consists of
  70the sequence tag and length octets, the mech OID DER encoding, and the
  71first two inner bytes, which indicate the token type.  The token
  72"body" consists of everything else.
  73
  74*/
  75
  76static int
  77der_length_size( int length)
  78{
  79        if (length < (1<<7))
  80                return(1);
  81        else if (length < (1<<8))
  82                return(2);
  83#if (SIZEOF_INT == 2)
  84        else
  85                return(3);
  86#else
  87        else if (length < (1<<16))
  88                return(3);
  89        else if (length < (1<<24))
  90                return(4);
  91        else
  92                return(5);
  93#endif
  94}
  95
  96static void
  97der_write_length(unsigned char **buf, int length)
  98{
  99        if (length < (1<<7)) {
 100                *(*buf)++ = (unsigned char) length;
 101        } else {
 102                *(*buf)++ = (unsigned char) (der_length_size(length)+127);
 103#if (SIZEOF_INT > 2)
 104                if (length >= (1<<24))
 105                        *(*buf)++ = (unsigned char) (length>>24);
 106                if (length >= (1<<16))
 107                        *(*buf)++ = (unsigned char) ((length>>16)&0xff);
 108#endif
 109                if (length >= (1<<8))
 110                        *(*buf)++ = (unsigned char) ((length>>8)&0xff);
 111                *(*buf)++ = (unsigned char) (length&0xff);
 112        }
 113}
 114
 115/* returns decoded length, or < 0 on failure.  Advances buf and
 116   decrements bufsize */
 117
 118static int
 119der_read_length(unsigned char **buf, int *bufsize)
 120{
 121        unsigned char sf;
 122        int ret;
 123
 124        if (*bufsize < 1)
 125                return(-1);
 126        sf = *(*buf)++;
 127        (*bufsize)--;
 128        if (sf & 0x80) {
 129                if ((sf &= 0x7f) > ((*bufsize)-1))
 130                        return(-1);
 131                if (sf > SIZEOF_INT)
 132                        return (-1);
 133                ret = 0;
 134                for (; sf; sf--) {
 135                        ret = (ret<<8) + (*(*buf)++);
 136                        (*bufsize)--;
 137                }
 138        } else {
 139                ret = sf;
 140        }
 141
 142        return(ret);
 143}
 144
 145/* returns the length of a token, given the mech oid and the body size */
 146
 147int
 148g_token_size(struct xdr_netobj *mech, unsigned int body_size)
 149{
 150        /* set body_size to sequence contents size */
 151        body_size += 2 + (int) mech->len;         /* NEED overflow check */
 152        return(1 + der_length_size(body_size) + body_size);
 153}
 154
 155EXPORT_SYMBOL_GPL(g_token_size);
 156
 157/* fills in a buffer with the token header.  The buffer is assumed to
 158   be the right size.  buf is advanced past the token header */
 159
 160void
 161g_make_token_header(struct xdr_netobj *mech, int body_size, unsigned char **buf)
 162{
 163        *(*buf)++ = 0x60;
 164        der_write_length(buf, 2 + mech->len + body_size);
 165        *(*buf)++ = 0x06;
 166        *(*buf)++ = (unsigned char) mech->len;
 167        TWRITE_STR(*buf, mech->data, ((int) mech->len));
 168}
 169
 170EXPORT_SYMBOL_GPL(g_make_token_header);
 171
 172/*
 173 * Given a buffer containing a token, reads and verifies the token,
 174 * leaving buf advanced past the token header, and setting body_size
 175 * to the number of remaining bytes.  Returns 0 on success,
 176 * G_BAD_TOK_HEADER for a variety of errors, and G_WRONG_MECH if the
 177 * mechanism in the token does not match the mech argument.  buf and
 178 * *body_size are left unmodified on error.
 179 */
 180u32
 181g_verify_token_header(struct xdr_netobj *mech, int *body_size,
 182                      unsigned char **buf_in, int toksize)
 183{
 184        unsigned char *buf = *buf_in;
 185        int seqsize;
 186        struct xdr_netobj toid;
 187        int ret = 0;
 188
 189        if ((toksize-=1) < 0)
 190                return(G_BAD_TOK_HEADER);
 191        if (*buf++ != 0x60)
 192                return(G_BAD_TOK_HEADER);
 193
 194        if ((seqsize = der_read_length(&buf, &toksize)) < 0)
 195                return(G_BAD_TOK_HEADER);
 196
 197        if (seqsize != toksize)
 198                return(G_BAD_TOK_HEADER);
 199
 200        if ((toksize-=1) < 0)
 201                return(G_BAD_TOK_HEADER);
 202        if (*buf++ != 0x06)
 203                return(G_BAD_TOK_HEADER);
 204
 205        if ((toksize-=1) < 0)
 206                return(G_BAD_TOK_HEADER);
 207        toid.len = *buf++;
 208
 209        if ((toksize-=toid.len) < 0)
 210                return(G_BAD_TOK_HEADER);
 211        toid.data = buf;
 212        buf+=toid.len;
 213
 214        if (! g_OID_equal(&toid, mech))
 215                ret = G_WRONG_MECH;
 216
 217   /* G_WRONG_MECH is not returned immediately because it's more important
 218      to return G_BAD_TOK_HEADER if the token header is in fact bad */
 219
 220        if ((toksize-=2) < 0)
 221                return(G_BAD_TOK_HEADER);
 222
 223        if (ret)
 224                return(ret);
 225
 226        if (!ret) {
 227                *buf_in = buf;
 228                *body_size = toksize;
 229        }
 230
 231        return(ret);
 232}
 233
 234EXPORT_SYMBOL_GPL(g_verify_token_header);
 235
 236