2005-04-16 15:20:36 -07:00
/*
* linux / net / sunrpc / gss_spkm3_token . c
*
* Copyright ( c ) 2003 The Regents of the University of Michigan .
* All rights reserved .
*
* Andy Adamson < andros @ umich . edu >
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
*
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED ` ` AS IS ' ' AND ANY EXPRESS OR IMPLIED
* WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR
* CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR
* BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING
* NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*
*/
# include <linux/types.h>
# include <linux/slab.h>
# include <linux/jiffies.h>
# include <linux/sunrpc/gss_spkm3.h>
# include <linux/random.h>
# include <linux/crypto.h>
# ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_AUTH
# endif
/*
* asn1_bitstring_len ( )
*
* calculate the asn1 bitstring length of the xdr_netobject
*/
void
asn1_bitstring_len ( struct xdr_netobj * in , int * enclen , int * zerobits )
{
int i , zbit = 0 , elen = in - > len ;
char * ptr ;
ptr = & in - > data [ in - > len - 1 ] ;
/* count trailing 0's */
for ( i = in - > len ; i > 0 ; i - - ) {
2007-02-09 15:38:13 -08:00
if ( * ptr = = 0 ) {
2005-04-16 15:20:36 -07:00
ptr - - ;
elen - - ;
} else
break ;
}
/* count number of 0 bits in final octet */
ptr = & in - > data [ elen - 1 ] ;
for ( i = 0 ; i < 8 ; i + + ) {
short mask = 0x01 ;
if ( ! ( ( mask < < i ) & * ptr ) )
zbit + + ;
else
break ;
}
* enclen = elen ;
* zerobits = zbit ;
}
/*
* decode_asn1_bitstring ( )
2007-02-09 15:38:13 -08:00
*
2005-04-16 15:20:36 -07:00
* decode a bitstring into a buffer of the expected length .
* enclen = bit string length
* explen = expected length ( define in rfc )
*/
int
decode_asn1_bitstring ( struct xdr_netobj * out , char * in , int enclen , int explen )
{
2006-07-21 14:51:30 -07:00
if ( ! ( out - > data = kzalloc ( explen , GFP_KERNEL ) ) )
2005-04-16 15:20:36 -07:00
return 0 ;
out - > len = explen ;
memcpy ( out - > data , in , enclen ) ;
return 1 ;
}
2007-02-09 15:38:13 -08:00
/*
2005-04-16 15:20:36 -07:00
* SPKMInnerContextToken choice SPKM_MIC asn1 token layout
2007-02-09 15:38:13 -08:00
*
2005-04-16 15:20:36 -07:00
* contextid is always 16 bytes plain data . max asn1 bitstring len = 17.
*
* tokenlen = pos [ 0 ] to end of token ( max pos [ 45 ] with MD5 cksum )
*
* pos value
* - - - - - - - - - -
* [ 0 ] a4 SPKM - MIC tag
2007-02-09 15:38:13 -08:00
* [ 1 ] ? ? innertoken length ( max 44 )
*
*
* tok_hdr piece of checksum data starts here
2005-04-16 15:20:36 -07:00
*
2007-02-09 15:38:13 -08:00
* the maximum mic - header len = 9 + 17 = 26
2005-04-16 15:20:36 -07:00
* mic - header
* - - - - - - - - - -
2007-02-09 15:38:13 -08:00
* [ 2 ] 30 SEQUENCE tag
* [ 3 ] ? ? mic - header length : ( max 23 ) = TokenID + ContextID
2005-04-16 15:20:36 -07:00
*
* TokenID - all fields constant and can be hardcoded
* - - - - - - -
* [ 4 ] 02 Type 2
2007-02-09 15:38:13 -08:00
* [ 5 ] 02 Length 2
2005-04-16 15:20:36 -07:00
* [ 6 ] [ 7 ] 01 01 TokenID ( SPKM_MIC_TOK )
*
* ContextID - encoded length not constant , calculated
* - - - - - - - - -
* [ 8 ] 03 Type 3
* [ 9 ] ? ? encoded length
* [ 10 ] ? ? ctxzbit
* [ 11 ] contextid
*
2007-02-09 15:38:13 -08:00
* mic_header piece of checksum data ends here .
2005-04-16 15:20:36 -07:00
*
* int - cksum - encoded length not constant , calculated
* - - - - - - - - -
* [ ? ? ] 03 Type 3
2007-02-09 15:38:13 -08:00
* [ ? ? ] ? ? encoded length
* [ ? ? ] ? ? md5zbit
2005-04-16 15:20:36 -07:00
* [ ? ? ] int - cksum ( NID_md5 = 16 )
*
2007-02-09 15:38:13 -08:00
* maximum SPKM - MIC innercontext token length =
* 10 + encoded contextid_size ( 17 max ) + 2 + encoded
2005-04-16 15:20:36 -07:00
* cksum_size ( 17 maxfor NID_md5 ) = 46
*/
/*
* spkm3_mic_header ( )
*
* Prepare the SPKM_MIC_TOK mic - header for check - sum calculation
* elen : 16 byte context id asn1 bitstring encoded length
*/
void
spkm3_mic_header ( unsigned char * * hdrbuf , unsigned int * hdrlen , unsigned char * ctxdata , int elen , int zbit )
{
char * hptr = * hdrbuf ;
char * top = * hdrbuf ;
* ( u8 * ) hptr + + = 0x30 ;
* ( u8 * ) hptr + + = elen + 7 ; /* on the wire header length */
/* tokenid */
* ( u8 * ) hptr + + = 0x02 ;
* ( u8 * ) hptr + + = 0x02 ;
* ( u8 * ) hptr + + = 0x01 ;
* ( u8 * ) hptr + + = 0x01 ;
/* coniextid */
* ( u8 * ) hptr + + = 0x03 ;
* ( u8 * ) hptr + + = elen + 1 ; /* add 1 to include zbit */
* ( u8 * ) hptr + + = zbit ;
memcpy ( hptr , ctxdata , elen ) ;
hptr + = elen ;
2006-12-04 20:22:34 -05:00
* hdrlen = hptr - top ;
2005-04-16 15:20:36 -07:00
}
2006-12-04 20:22:34 -05:00
/*
2005-04-16 15:20:36 -07:00
* spkm3_mic_innercontext_token ( )
*
2007-02-09 15:38:13 -08:00
* * tokp points to the beginning of the SPKM_MIC token described
* in rfc 2025 , section 3.2 .1 :
2005-04-16 15:20:36 -07:00
*
2006-01-03 09:56:00 +01:00
* toklen is the inner token length
2005-04-16 15:20:36 -07:00
*/
void
spkm3_make_mic_token ( unsigned char * * tokp , int toklen , struct xdr_netobj * mic_hdr , struct xdr_netobj * md5cksum , int md5elen , int md5zbit )
{
unsigned char * ict = * tokp ;
* ( u8 * ) ict + + = 0xa4 ;
2006-01-03 09:56:00 +01:00
* ( u8 * ) ict + + = toklen ;
2005-04-16 15:20:36 -07:00
memcpy ( ict , mic_hdr - > data , mic_hdr - > len ) ;
ict + = mic_hdr - > len ;
* ( u8 * ) ict + + = 0x03 ;
* ( u8 * ) ict + + = md5elen + 1 ; /* add 1 to include zbit */
* ( u8 * ) ict + + = md5zbit ;
memcpy ( ict , md5cksum - > data , md5elen ) ;
}
u32
spkm3_verify_mic_token ( unsigned char * * tokp , int * mic_hdrlen , unsigned char * * cksum )
{
struct xdr_netobj spkm3_ctx_id = { . len = 0 , . data = NULL } ;
unsigned char * ptr = * tokp ;
int ctxelen ;
u32 ret = GSS_S_DEFECTIVE_TOKEN ;
/* spkm3 innercontext token preamble */
if ( ( ptr [ 0 ] ! = 0xa4 ) | | ( ptr [ 2 ] ! = 0x30 ) ) {
2007-01-31 12:14:05 -05:00
dprintk ( " RPC: BAD SPKM ictoken preamble \n " ) ;
2005-04-16 15:20:36 -07:00
goto out ;
}
* mic_hdrlen = ptr [ 3 ] ;
/* token type */
if ( ( ptr [ 4 ] ! = 0x02 ) | | ( ptr [ 5 ] ! = 0x02 ) ) {
2007-01-31 12:14:05 -05:00
dprintk ( " RPC: BAD asn1 SPKM3 token type \n " ) ;
2005-04-16 15:20:36 -07:00
goto out ;
}
/* only support SPKM_MIC_TOK */
if ( ( ptr [ 6 ] ! = 0x01 ) | | ( ptr [ 7 ] ! = 0x01 ) ) {
2007-01-31 12:14:05 -05:00
dprintk ( " RPC: ERROR unsupported SPKM3 token \n " ) ;
2005-04-16 15:20:36 -07:00
goto out ;
}
/* contextid */
if ( ptr [ 8 ] ! = 0x03 ) {
2007-01-31 12:14:05 -05:00
dprintk ( " RPC: BAD SPKM3 asn1 context-id type \n " ) ;
2005-04-16 15:20:36 -07:00
goto out ;
}
ctxelen = ptr [ 9 ] ;
if ( ctxelen > 17 ) { /* length includes asn1 zbit octet */
2007-01-31 12:14:05 -05:00
dprintk ( " RPC: BAD SPKM3 contextid len %d \n " , ctxelen ) ;
2005-04-16 15:20:36 -07:00
goto out ;
}
/* ignore ptr[10] */
if ( ! decode_asn1_bitstring ( & spkm3_ctx_id , & ptr [ 11 ] , ctxelen - 1 , 16 ) )
goto out ;
/*
2007-02-09 15:38:13 -08:00
* in the current implementation : the optional int - alg is not present
* so the default int - alg ( md5 ) is used the optional snd - seq field is
* also not present
2005-04-16 15:20:36 -07:00
*/
if ( * mic_hdrlen ! = 6 + ctxelen ) {
2007-01-31 12:14:05 -05:00
dprintk ( " RPC: BAD SPKM_ MIC_TOK header len %d: we only "
" support default int-alg (should be absent) "
" and do not support snd-seq \n " , * mic_hdrlen ) ;
2005-04-16 15:20:36 -07:00
goto out ;
}
/* checksum */
2007-02-09 15:38:13 -08:00
* cksum = ( & ptr [ 10 ] + ctxelen ) ; /* ctxelen includes ptr[10] */
2005-04-16 15:20:36 -07:00
ret = GSS_S_COMPLETE ;
out :
2005-11-08 09:41:34 -08:00
kfree ( spkm3_ctx_id . data ) ;
2005-04-16 15:20:36 -07:00
return ret ;
}