2005-04-16 15:20:36 -07:00
/*
* linux / net / sunrpc / gss_spkm3_seal . 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>
2006-12-04 20:22:34 -05:00
# include <linux/pagemap.h>
# include <linux/scatterlist.h>
# include <linux/sunrpc/xdr.h>
2005-04-16 15:20:36 -07:00
# ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_AUTH
# endif
2006-12-04 20:22:34 -05:00
const struct xdr_netobj hmac_md5_oid = { 8 , " \x2B \x06 \x01 \x05 \x05 \x08 \x01 \x01 " } ;
const struct xdr_netobj cast5_cbc_oid = { 9 , " \x2A \x86 \x48 \x86 \xF6 \x7D \x07 \x42 \x0A " } ;
2005-04-16 15:20:36 -07:00
/*
* spkm3_make_token ( )
*
* Only SPKM_MIC_TOK with md5 intg - alg is supported
*/
u32
2005-10-13 16:55:18 -04:00
spkm3_make_token ( struct spkm3_ctx * ctx ,
2005-04-16 15:20:36 -07:00
struct xdr_buf * text , struct xdr_netobj * token ,
int toktype )
{
s32 checksum_type ;
char tokhdrbuf [ 25 ] ;
2006-03-20 23:23:11 -05:00
char cksumdata [ 16 ] ;
struct xdr_netobj md5cksum = { . len = 0 , . data = cksumdata } ;
2005-04-16 15:20:36 -07:00
struct xdr_netobj mic_hdr = { . len = 0 , . data = tokhdrbuf } ;
2006-01-03 09:56:00 +01:00
int tokenlen = 0 ;
2005-04-16 15:20:36 -07:00
unsigned char * ptr ;
s32 now ;
int ctxelen = 0 , ctxzbit = 0 ;
int md5elen = 0 , md5zbit = 0 ;
now = jiffies ;
if ( ctx - > ctx_id . len ! = 16 ) {
2007-01-31 12:14:05 -05:00
dprintk ( " RPC: spkm3_make_token BAD ctx_id.len %d \n " ,
2006-12-04 20:22:34 -05:00
ctx - > ctx_id . len ) ;
2005-04-16 15:20:36 -07:00
goto out_err ;
}
2006-12-04 20:22:34 -05:00
if ( ! g_OID_equal ( & ctx - > intg_alg , & hmac_md5_oid ) ) {
2007-01-31 12:14:05 -05:00
dprintk ( " RPC: gss_spkm3_seal: unsupported I-ALG "
" algorithm. only support hmac-md5 I-ALG. \n " ) ;
2006-12-04 20:22:34 -05:00
goto out_err ;
} else
checksum_type = CKSUMTYPE_HMAC_MD5 ;
if ( ! g_OID_equal ( & ctx - > conf_alg , & cast5_cbc_oid ) ) {
2007-01-31 12:14:05 -05:00
dprintk ( " RPC: gss_spkm3_seal: unsupported C-ALG "
" algorithm \n " ) ;
2005-04-16 15:20:36 -07:00
goto out_err ;
}
if ( toktype = = SPKM_MIC_TOK ) {
/* Calculate checksum over the mic-header */
asn1_bitstring_len ( & ctx - > ctx_id , & ctxelen , & ctxzbit ) ;
spkm3_mic_header ( & mic_hdr . data , & mic_hdr . len , ctx - > ctx_id . data ,
2006-12-04 20:22:34 -05:00
ctxelen , ctxzbit ) ;
if ( make_spkm3_checksum ( checksum_type , & ctx - > derived_integ_key ,
( char * ) mic_hdr . data , mic_hdr . len ,
text , 0 , & md5cksum ) )
2005-04-16 15:20:36 -07:00
goto out_err ;
asn1_bitstring_len ( & md5cksum , & md5elen , & md5zbit ) ;
2006-01-03 09:56:00 +01:00
tokenlen = 10 + ctxelen + 1 + md5elen + 1 ;
2005-04-16 15:20:36 -07:00
/* Create token header using generic routines */
2006-01-03 09:56:00 +01:00
token - > len = g_token_size ( & ctx - > mech_used , tokenlen ) ;
2005-04-16 15:20:36 -07:00
ptr = token - > data ;
2006-01-03 09:56:00 +01:00
g_make_token_header ( & ctx - > mech_used , tokenlen , & ptr ) ;
2005-04-16 15:20:36 -07:00
spkm3_make_mic_token ( & ptr , tokenlen , & mic_hdr , & md5cksum , md5elen , md5zbit ) ;
} else if ( toktype = = SPKM_WRAP_TOK ) { /* Not Supported */
2007-01-31 12:14:05 -05:00
dprintk ( " RPC: gss_spkm3_seal: SPKM_WRAP_TOK "
" not supported \n " ) ;
2005-04-16 15:20:36 -07:00
goto out_err ;
}
/* XXX need to implement sequence numbers, and ctx->expired */
return GSS_S_COMPLETE ;
out_err :
token - > data = NULL ;
token - > len = 0 ;
return GSS_S_FAILURE ;
}
2006-12-04 20:22:34 -05:00
static int
spkm3_checksummer ( struct scatterlist * sg , void * data )
{
struct hash_desc * desc = data ;
return crypto_hash_update ( desc , sg , sg - > length ) ;
}
/* checksum the plaintext data and hdrlen bytes of the token header */
s32
make_spkm3_checksum ( s32 cksumtype , struct xdr_netobj * key , char * header ,
unsigned int hdrlen , struct xdr_buf * body ,
unsigned int body_offset , struct xdr_netobj * cksum )
{
char * cksumname ;
struct hash_desc desc ; /* XXX add to ctx? */
struct scatterlist sg [ 1 ] ;
int err ;
switch ( cksumtype ) {
case CKSUMTYPE_HMAC_MD5 :
2007-02-10 01:33:25 -05:00
cksumname = " hmac(md5) " ;
2006-12-04 20:22:34 -05:00
break ;
default :
2007-01-31 12:14:05 -05:00
dprintk ( " RPC: spkm3_make_checksum: "
2006-12-04 20:22:34 -05:00
" unsupported checksum %d " , cksumtype ) ;
return GSS_S_FAILURE ;
}
if ( key - > data = = NULL | | key - > len < = 0 ) return GSS_S_FAILURE ;
desc . tfm = crypto_alloc_hash ( cksumname , 0 , CRYPTO_ALG_ASYNC ) ;
if ( IS_ERR ( desc . tfm ) )
return GSS_S_FAILURE ;
cksum - > len = crypto_hash_digestsize ( desc . tfm ) ;
desc . flags = CRYPTO_TFM_REQ_MAY_SLEEP ;
err = crypto_hash_setkey ( desc . tfm , key - > data , key - > len ) ;
if ( err )
goto out ;
2007-02-10 01:33:27 -05:00
err = crypto_hash_init ( & desc ) ;
if ( err )
goto out ;
2007-10-27 00:52:07 -07:00
sg_init_one ( sg , header , hdrlen ) ;
2007-02-10 01:33:25 -05:00
crypto_hash_update ( & desc , sg , sg - > length ) ;
2006-12-04 20:22:34 -05:00
xdr_process_buf ( body , body_offset , body - > len - body_offset ,
spkm3_checksummer , & desc ) ;
crypto_hash_final ( & desc , cksum - > data ) ;
out :
crypto_free_hash ( desc . tfm ) ;
return err ? GSS_S_FAILURE : 0 ;
}