2007-04-26 15:48:28 -07:00
/* RxRPC key management
*
* Copyright ( C ) 2007 Red Hat , Inc . All Rights Reserved .
* Written by David Howells ( dhowells @ redhat . com )
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*
* RxRPC keys should have a description of describing their purpose :
* " afs@CAMBRIDGE.REDHAT.COM>
*/
# include <linux/module.h>
# include <linux/net.h>
# include <linux/skbuff.h>
2007-10-16 23:29:46 -07:00
# include <linux/key-type.h>
2007-04-26 15:48:28 -07:00
# include <linux/crypto.h>
# include <net/sock.h>
# include <net/af_rxrpc.h>
# include <keys/rxrpc-type.h>
# include <keys/user-type.h>
# include "ar-internal.h"
static int rxrpc_instantiate ( struct key * , const void * , size_t ) ;
static int rxrpc_instantiate_s ( struct key * , const void * , size_t ) ;
static void rxrpc_destroy ( struct key * ) ;
static void rxrpc_destroy_s ( struct key * ) ;
static void rxrpc_describe ( const struct key * , struct seq_file * ) ;
/*
* rxrpc defined keys take an arbitrary string as the description and an
* arbitrary blob of data as the payload
*/
struct key_type key_type_rxrpc = {
. name = " rxrpc " ,
. instantiate = rxrpc_instantiate ,
. match = user_match ,
. destroy = rxrpc_destroy ,
. describe = rxrpc_describe ,
} ;
EXPORT_SYMBOL ( key_type_rxrpc ) ;
/*
* rxrpc server defined keys take " <serviceId>:<securityIndex> " as the
* description and an 8 - byte decryption key as the payload
*/
struct key_type key_type_rxrpc_s = {
. name = " rxrpc_s " ,
. instantiate = rxrpc_instantiate_s ,
. match = user_match ,
. destroy = rxrpc_destroy_s ,
. describe = rxrpc_describe ,
} ;
/*
* instantiate an rxrpc defined key
* data should be of the form :
* OFFSET LEN CONTENT
* 0 4 key interface version number
* 4 2 security index ( type )
* 6 2 ticket length
* 8 4 key expiry time ( time_t )
* 12 4 kvno
* 16 8 session key
* 24 [ len ] ticket
*
* if no data is provided , then a no - security key is made
*/
static int rxrpc_instantiate ( struct key * key , const void * data , size_t datalen )
{
const struct rxkad_key * tsec ;
struct rxrpc_key_payload * upayload ;
size_t plen ;
u32 kver ;
int ret ;
_enter ( " {%x},,%zu " , key_serial ( key ) , datalen ) ;
/* handle a no-security key */
if ( ! data & & datalen = = 0 )
return 0 ;
/* get the key interface version number */
ret = - EINVAL ;
if ( datalen < = 4 | | ! data )
goto error ;
memcpy ( & kver , data , sizeof ( kver ) ) ;
data + = sizeof ( kver ) ;
datalen - = sizeof ( kver ) ;
_debug ( " KEY I/F VERSION: %u " , kver ) ;
ret = - EKEYREJECTED ;
if ( kver ! = 1 )
goto error ;
/* deal with a version 1 key */
ret = - EINVAL ;
if ( datalen < sizeof ( * tsec ) )
goto error ;
tsec = data ;
if ( datalen ! = sizeof ( * tsec ) + tsec - > ticket_len )
goto error ;
_debug ( " SCIX: %u " , tsec - > security_index ) ;
_debug ( " TLEN: %u " , tsec - > ticket_len ) ;
_debug ( " EXPY: %x " , tsec - > expiry ) ;
_debug ( " KVNO: %u " , tsec - > kvno ) ;
_debug ( " SKEY: %02x%02x%02x%02x%02x%02x%02x%02x " ,
tsec - > session_key [ 0 ] , tsec - > session_key [ 1 ] ,
tsec - > session_key [ 2 ] , tsec - > session_key [ 3 ] ,
tsec - > session_key [ 4 ] , tsec - > session_key [ 5 ] ,
tsec - > session_key [ 6 ] , tsec - > session_key [ 7 ] ) ;
if ( tsec - > ticket_len > = 8 )
_debug ( " TCKT: %02x%02x%02x%02x%02x%02x%02x%02x " ,
tsec - > ticket [ 0 ] , tsec - > ticket [ 1 ] ,
tsec - > ticket [ 2 ] , tsec - > ticket [ 3 ] ,
tsec - > ticket [ 4 ] , tsec - > ticket [ 5 ] ,
tsec - > ticket [ 6 ] , tsec - > ticket [ 7 ] ) ;
ret = - EPROTONOSUPPORT ;
if ( tsec - > security_index ! = 2 )
goto error ;
key - > type_data . x [ 0 ] = tsec - > security_index ;
plen = sizeof ( * upayload ) + tsec - > ticket_len ;
ret = key_payload_reserve ( key , plen ) ;
if ( ret < 0 )
goto error ;
ret = - ENOMEM ;
upayload = kmalloc ( plen , GFP_KERNEL ) ;
if ( ! upayload )
goto error ;
/* attach the data */
memcpy ( & upayload - > k , tsec , sizeof ( * tsec ) ) ;
memcpy ( & upayload - > k . ticket , ( void * ) tsec + sizeof ( * tsec ) ,
tsec - > ticket_len ) ;
key - > payload . data = upayload ;
key - > expiry = tsec - > expiry ;
ret = 0 ;
error :
return ret ;
}
/*
* instantiate a server secret key
* data should be a pointer to the 8 - byte secret key
*/
static int rxrpc_instantiate_s ( struct key * key , const void * data ,
size_t datalen )
{
struct crypto_blkcipher * ci ;
_enter ( " {%x},,%zu " , key_serial ( key ) , datalen ) ;
if ( datalen ! = 8 )
return - EINVAL ;
memcpy ( & key - > type_data , data , 8 ) ;
ci = crypto_alloc_blkcipher ( " pcbc(des) " , 0 , CRYPTO_ALG_ASYNC ) ;
if ( IS_ERR ( ci ) ) {
_leave ( " = %ld " , PTR_ERR ( ci ) ) ;
return PTR_ERR ( ci ) ;
}
if ( crypto_blkcipher_setkey ( ci , data , 8 ) < 0 )
BUG ( ) ;
key - > payload . data = ci ;
_leave ( " = 0 " ) ;
return 0 ;
}
/*
* dispose of the data dangling from the corpse of a rxrpc key
*/
static void rxrpc_destroy ( struct key * key )
{
kfree ( key - > payload . data ) ;
}
/*
* dispose of the data dangling from the corpse of a rxrpc key
*/
static void rxrpc_destroy_s ( struct key * key )
{
if ( key - > payload . data ) {
crypto_free_blkcipher ( key - > payload . data ) ;
key - > payload . data = NULL ;
}
}
/*
* describe the rxrpc key
*/
static void rxrpc_describe ( const struct key * key , struct seq_file * m )
{
seq_puts ( m , key - > description ) ;
}
/*
* grab the security key for a socket
*/
int rxrpc_request_key ( struct rxrpc_sock * rx , char __user * optval , int optlen )
{
struct key * key ;
char * description ;
_enter ( " " ) ;
if ( optlen < = 0 | | optlen > PAGE_SIZE - 1 )
return - EINVAL ;
description = kmalloc ( optlen + 1 , GFP_KERNEL ) ;
if ( ! description )
return - ENOMEM ;
if ( copy_from_user ( description , optval , optlen ) ) {
kfree ( description ) ;
return - EFAULT ;
}
description [ optlen ] = 0 ;
key = request_key ( & key_type_rxrpc , description , NULL ) ;
if ( IS_ERR ( key ) ) {
kfree ( description ) ;
_leave ( " = %ld " , PTR_ERR ( key ) ) ;
return PTR_ERR ( key ) ;
}
rx - > key = key ;
kfree ( description ) ;
_leave ( " = 0 [key %x] " , key - > serial ) ;
return 0 ;
}
/*
* grab the security keyring for a server socket
*/
int rxrpc_server_keyring ( struct rxrpc_sock * rx , char __user * optval ,
int optlen )
{
struct key * key ;
char * description ;
_enter ( " " ) ;
if ( optlen < = 0 | | optlen > PAGE_SIZE - 1 )
return - EINVAL ;
description = kmalloc ( optlen + 1 , GFP_KERNEL ) ;
if ( ! description )
return - ENOMEM ;
if ( copy_from_user ( description , optval , optlen ) ) {
kfree ( description ) ;
return - EFAULT ;
}
description [ optlen ] = 0 ;
key = request_key ( & key_type_keyring , description , NULL ) ;
if ( IS_ERR ( key ) ) {
kfree ( description ) ;
_leave ( " = %ld " , PTR_ERR ( key ) ) ;
return PTR_ERR ( key ) ;
}
rx - > securities = key ;
kfree ( description ) ;
_leave ( " = 0 [key %x] " , key - > serial ) ;
return 0 ;
}
/*
* generate a server data key
*/
int rxrpc_get_server_data_key ( struct rxrpc_connection * conn ,
const void * session_key ,
time_t expiry ,
u32 kvno )
{
struct key * key ;
int ret ;
struct {
u32 kver ;
struct rxkad_key tsec ;
} data ;
_enter ( " " ) ;
key = key_alloc ( & key_type_rxrpc , " x " , 0 , 0 , current , 0 ,
KEY_ALLOC_NOT_IN_QUOTA ) ;
if ( IS_ERR ( key ) ) {
_leave ( " = -ENOMEM [alloc %ld] " , PTR_ERR ( key ) ) ;
return - ENOMEM ;
}
_debug ( " key %d " , key_serial ( key ) ) ;
data . kver = 1 ;
data . tsec . security_index = 2 ;
data . tsec . ticket_len = 0 ;
data . tsec . expiry = expiry ;
data . tsec . kvno = 0 ;
memcpy ( & data . tsec . session_key , session_key ,
sizeof ( data . tsec . session_key ) ) ;
ret = key_instantiate_and_link ( key , & data , sizeof ( data ) , NULL , NULL ) ;
if ( ret < 0 )
goto error ;
conn - > key = key ;
_leave ( " = 0 [%d] " , key_serial ( key ) ) ;
return 0 ;
error :
key_revoke ( key ) ;
key_put ( key ) ;
_leave ( " = -ENOMEM [ins %d] " , ret ) ;
return - ENOMEM ;
}
EXPORT_SYMBOL ( rxrpc_get_server_data_key ) ;
2007-10-16 23:29:46 -07:00
/**
* rxrpc_get_null_key - Generate a null RxRPC key
* @ keyname : The name to give the key .
*
* Generate a null RxRPC key that can be used to indicate anonymous security is
* required for a particular domain .
*/
struct key * rxrpc_get_null_key ( const char * keyname )
{
struct key * key ;
int ret ;
key = key_alloc ( & key_type_rxrpc , keyname , 0 , 0 , current ,
KEY_POS_SEARCH , KEY_ALLOC_NOT_IN_QUOTA ) ;
if ( IS_ERR ( key ) )
return key ;
ret = key_instantiate_and_link ( key , NULL , 0 , NULL , NULL ) ;
if ( ret < 0 ) {
key_revoke ( key ) ;
key_put ( key ) ;
return ERR_PTR ( ret ) ;
}
return key ;
}
EXPORT_SYMBOL ( rxrpc_get_null_key ) ;