2014-12-26 01:00:06 +03:00
/*
* algif_rng : User - space interface for random number generators
*
* This file provides the user - space API for random number generators .
*
* Copyright ( C ) 2014 , Stephan Mueller < smueller @ chronox . de >
*
* 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 , and the entire permission notice in its entirety ,
* including the disclaimer of warranties .
* 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. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission .
*
* ALTERNATIVELY , this product may be distributed under the terms of
* the GNU General Public License , in which case the provisions of the GPL2
* are required INSTEAD OF the above restrictions . ( This clause is
* necessary due to a potential bad interaction between the GPL and
* the restrictions contained in a BSD - style copyright . )
*
* 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 , ALL OF
* WHICH ARE HEREBY DISCLAIMED . IN NO EVENT SHALL THE AUTHOR 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 NOT ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE .
*/
2020-09-18 18:42:16 +03:00
# include <linux/capability.h>
2014-12-26 01:00:06 +03:00
# include <linux/module.h>
# include <crypto/rng.h>
# include <linux/random.h>
# include <crypto/if_alg.h>
# include <linux/net.h>
# include <net/sock.h>
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Stephan Mueller <smueller@chronox.de> " ) ;
MODULE_DESCRIPTION ( " User-space interface for random number generators " ) ;
struct rng_ctx {
# define MAXSIZE 128
unsigned int len ;
struct crypto_rng * drng ;
2020-09-18 18:42:16 +03:00
u8 * addtl ;
size_t addtl_len ;
2014-12-26 01:00:06 +03:00
} ;
2020-09-18 18:42:16 +03:00
struct rng_parent_ctx {
struct crypto_rng * drng ;
u8 * entropy ;
} ;
static void rng_reset_addtl ( struct rng_ctx * ctx )
2014-12-26 01:00:06 +03:00
{
2020-09-18 18:42:16 +03:00
kfree_sensitive ( ctx - > addtl ) ;
ctx - > addtl = NULL ;
ctx - > addtl_len = 0 ;
}
static int _rng_recvmsg ( struct crypto_rng * drng , struct msghdr * msg , size_t len ,
u8 * addtl , size_t addtl_len )
{
int err = 0 ;
2014-12-26 01:00:06 +03:00
int genlen = 0 ;
u8 result [ MAXSIZE ] ;
if ( len = = 0 )
return 0 ;
if ( len > MAXSIZE )
len = MAXSIZE ;
/*
* although not strictly needed , this is a precaution against coding
* errors
*/
memset ( result , 0 , len ) ;
/*
* The enforcement of a proper seeding of an RNG is done within an
* RNG implementation . Some RNGs ( DRBG , krng ) do not need specific
* seeding as they automatically seed . The X9 .31 DRNG will return
* an error if it was not seeded properly .
*/
2020-09-18 18:42:16 +03:00
genlen = crypto_rng_generate ( drng , addtl , addtl_len , result , len ) ;
2014-12-26 01:00:06 +03:00
if ( genlen < 0 )
return genlen ;
err = memcpy_to_msg ( msg , result , len ) ;
2015-03-13 13:44:07 +03:00
memzero_explicit ( result , len ) ;
2014-12-26 01:00:06 +03:00
return err ? err : len ;
}
2020-09-18 18:42:16 +03:00
static int rng_recvmsg ( struct socket * sock , struct msghdr * msg , size_t len ,
int flags )
{
struct sock * sk = sock - > sk ;
struct alg_sock * ask = alg_sk ( sk ) ;
struct rng_ctx * ctx = ask - > private ;
return _rng_recvmsg ( ctx - > drng , msg , len , NULL , 0 ) ;
}
static int rng_test_recvmsg ( struct socket * sock , struct msghdr * msg , size_t len ,
int flags )
{
struct sock * sk = sock - > sk ;
struct alg_sock * ask = alg_sk ( sk ) ;
struct rng_ctx * ctx = ask - > private ;
int ret ;
lock_sock ( sock - > sk ) ;
ret = _rng_recvmsg ( ctx - > drng , msg , len , ctx - > addtl , ctx - > addtl_len ) ;
rng_reset_addtl ( ctx ) ;
release_sock ( sock - > sk ) ;
return ret ;
}
static int rng_test_sendmsg ( struct socket * sock , struct msghdr * msg , size_t len )
{
int err ;
struct alg_sock * ask = alg_sk ( sock - > sk ) ;
struct rng_ctx * ctx = ask - > private ;
lock_sock ( sock - > sk ) ;
if ( len > MAXSIZE ) {
err = - EMSGSIZE ;
goto unlock ;
}
rng_reset_addtl ( ctx ) ;
ctx - > addtl = kmalloc ( len , GFP_KERNEL ) ;
if ( ! ctx - > addtl ) {
err = - ENOMEM ;
goto unlock ;
}
err = memcpy_from_msg ( ctx - > addtl , msg , len ) ;
if ( err ) {
rng_reset_addtl ( ctx ) ;
goto unlock ;
}
ctx - > addtl_len = len ;
unlock :
release_sock ( sock - > sk ) ;
return err ? err : len ;
}
2014-12-26 01:00:06 +03:00
static struct proto_ops algif_rng_ops = {
. family = PF_ALG ,
. connect = sock_no_connect ,
. socketpair = sock_no_socketpair ,
. getname = sock_no_getname ,
. ioctl = sock_no_ioctl ,
. listen = sock_no_listen ,
. shutdown = sock_no_shutdown ,
. mmap = sock_no_mmap ,
. bind = sock_no_bind ,
. accept = sock_no_accept ,
. sendmsg = sock_no_sendmsg ,
. sendpage = sock_no_sendpage ,
. release = af_alg_release ,
. recvmsg = rng_recvmsg ,
} ;
2020-09-18 18:42:16 +03:00
static struct proto_ops __maybe_unused algif_rng_test_ops = {
. family = PF_ALG ,
. connect = sock_no_connect ,
. socketpair = sock_no_socketpair ,
. getname = sock_no_getname ,
. ioctl = sock_no_ioctl ,
. listen = sock_no_listen ,
. shutdown = sock_no_shutdown ,
. mmap = sock_no_mmap ,
. bind = sock_no_bind ,
. accept = sock_no_accept ,
. sendpage = sock_no_sendpage ,
. release = af_alg_release ,
. recvmsg = rng_test_recvmsg ,
. sendmsg = rng_test_sendmsg ,
} ;
2014-12-26 01:00:06 +03:00
static void * rng_bind ( const char * name , u32 type , u32 mask )
{
2020-09-18 18:42:16 +03:00
struct rng_parent_ctx * pctx ;
struct crypto_rng * rng ;
pctx = kzalloc ( sizeof ( * pctx ) , GFP_KERNEL ) ;
if ( ! pctx )
return ERR_PTR ( - ENOMEM ) ;
rng = crypto_alloc_rng ( name , type , mask ) ;
if ( IS_ERR ( rng ) ) {
kfree ( pctx ) ;
return ERR_CAST ( rng ) ;
}
pctx - > drng = rng ;
return pctx ;
2014-12-26 01:00:06 +03:00
}
static void rng_release ( void * private )
{
2020-09-18 18:42:16 +03:00
struct rng_parent_ctx * pctx = private ;
if ( unlikely ( ! pctx ) )
return ;
crypto_free_rng ( pctx - > drng ) ;
kfree_sensitive ( pctx - > entropy ) ;
kfree_sensitive ( pctx ) ;
2014-12-26 01:00:06 +03:00
}
static void rng_sock_destruct ( struct sock * sk )
{
struct alg_sock * ask = alg_sk ( sk ) ;
struct rng_ctx * ctx = ask - > private ;
2020-09-18 18:42:16 +03:00
rng_reset_addtl ( ctx ) ;
2014-12-26 01:00:06 +03:00
sock_kfree_s ( sk , ctx , ctx - > len ) ;
af_alg_release_parent ( sk ) ;
}
static int rng_accept_parent ( void * private , struct sock * sk )
{
struct rng_ctx * ctx ;
2020-09-18 18:42:16 +03:00
struct rng_parent_ctx * pctx = private ;
2014-12-26 01:00:06 +03:00
struct alg_sock * ask = alg_sk ( sk ) ;
unsigned int len = sizeof ( * ctx ) ;
ctx = sock_kmalloc ( sk , len , GFP_KERNEL ) ;
if ( ! ctx )
return - ENOMEM ;
ctx - > len = len ;
2020-09-18 18:42:16 +03:00
ctx - > addtl = NULL ;
ctx - > addtl_len = 0 ;
2014-12-26 01:00:06 +03:00
/*
* No seeding done at that point - - if multiple accepts are
* done on one RNG instance , each resulting FD points to the same
* state of the RNG .
*/
2020-09-18 18:42:16 +03:00
ctx - > drng = pctx - > drng ;
2014-12-26 01:00:06 +03:00
ask - > private = ctx ;
sk - > sk_destruct = rng_sock_destruct ;
2020-09-18 18:42:16 +03:00
/*
* Non NULL pctx - > entropy means that CAVP test has been initiated on
* this socket , replace proto_ops algif_rng_ops with algif_rng_test_ops .
*/
if ( IS_ENABLED ( CONFIG_CRYPTO_USER_API_RNG_CAVP ) & & pctx - > entropy )
sk - > sk_socket - > ops = & algif_rng_test_ops ;
2014-12-26 01:00:06 +03:00
return 0 ;
}
static int rng_setkey ( void * private , const u8 * seed , unsigned int seedlen )
{
2020-09-18 18:42:16 +03:00
struct rng_parent_ctx * pctx = private ;
2014-12-26 01:00:06 +03:00
/*
* Check whether seedlen is of sufficient size is done in RNG
* implementations .
*/
2020-09-18 18:42:16 +03:00
return crypto_rng_reset ( pctx - > drng , seed , seedlen ) ;
}
static int __maybe_unused rng_setentropy ( void * private , sockptr_t entropy ,
unsigned int len )
{
struct rng_parent_ctx * pctx = private ;
u8 * kentropy = NULL ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EACCES ;
if ( pctx - > entropy )
return - EINVAL ;
if ( len > MAXSIZE )
return - EMSGSIZE ;
if ( len ) {
kentropy = memdup_sockptr ( entropy , len ) ;
if ( IS_ERR ( kentropy ) )
return PTR_ERR ( kentropy ) ;
}
crypto_rng_alg ( pctx - > drng ) - > set_ent ( pctx - > drng , kentropy , len ) ;
/*
* Since rng doesn ' t perform any memory management for the entropy
* buffer , save kentropy pointer to pctx now to free it after use .
*/
pctx - > entropy = kentropy ;
return 0 ;
2014-12-26 01:00:06 +03:00
}
static const struct af_alg_type algif_type_rng = {
. bind = rng_bind ,
. release = rng_release ,
. accept = rng_accept_parent ,
. setkey = rng_setkey ,
2020-09-18 18:42:16 +03:00
# ifdef CONFIG_CRYPTO_USER_API_RNG_CAVP
. setentropy = rng_setentropy ,
# endif
2014-12-26 01:00:06 +03:00
. ops = & algif_rng_ops ,
. name = " rng " ,
. owner = THIS_MODULE
} ;
static int __init rng_init ( void )
{
return af_alg_register_type ( & algif_type_rng ) ;
}
2015-01-14 04:14:41 +03:00
static void __exit rng_exit ( void )
2014-12-26 01:00:06 +03:00
{
int err = af_alg_unregister_type ( & algif_type_rng ) ;
BUG_ON ( err ) ;
}
module_init ( rng_init ) ;
module_exit ( rng_exit ) ;