2012-09-21 23:24:55 +01:00
/* In-software asymmetric public-key crypto subtype
*
* See Documentation / crypto / asymmetric - keys . txt
*
* Copyright ( C ) 2012 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 Licence
* as published by the Free Software Foundation ; either version
* 2 of the Licence , or ( at your option ) any later version .
*/
# define pr_fmt(fmt) "PKEY: "fmt
# include <linux/module.h>
# include <linux/export.h>
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/seq_file.h>
2016-03-03 21:49:27 +00:00
# include <linux/scatterlist.h>
2012-09-21 23:24:55 +01:00
# include <keys/asymmetric-subtype.h>
2016-02-02 10:08:53 -08:00
# include <crypto/public_key.h>
2016-03-03 21:49:27 +00:00
# include <crypto/akcipher.h>
2012-09-21 23:24:55 +01:00
MODULE_LICENSE ( " GPL " ) ;
/*
* Provide a part of a description of the key for / proc / keys .
*/
static void public_key_describe ( const struct key * asymmetric_key ,
struct seq_file * m )
{
2015-10-21 14:04:48 +01:00
struct public_key * key = asymmetric_key - > payload . data [ asym_crypto ] ;
2012-09-21 23:24:55 +01:00
if ( key )
2016-03-03 21:49:27 +00:00
seq_printf ( m , " %s.%s " , key - > id_type , key - > pkey_algo ) ;
2012-09-21 23:24:55 +01:00
}
/*
* Destroy a public key algorithm key .
*/
2016-04-06 16:13:33 +01:00
void public_key_free ( struct public_key * key )
2012-09-21 23:24:55 +01:00
{
2016-04-06 16:13:33 +01:00
if ( key ) {
2016-02-02 10:08:53 -08:00
kfree ( key - > key ) ;
2016-04-06 16:13:33 +01:00
kfree ( key ) ;
}
}
EXPORT_SYMBOL_GPL ( public_key_free ) ;
/*
* Destroy a public key algorithm key .
*/
static void public_key_destroy ( void * payload0 , void * payload3 )
{
public_key_free ( payload0 ) ;
public_key_signature_free ( payload3 ) ;
2012-09-21 23:24:55 +01:00
}
2016-03-03 21:49:27 +00:00
struct public_key_completion {
struct completion completion ;
int err ;
} ;
static void public_key_verify_done ( struct crypto_async_request * req , int err )
{
struct public_key_completion * compl = req - > data ;
if ( err = = - EINPROGRESS )
return ;
compl - > err = err ;
complete ( & compl - > completion ) ;
}
2012-09-21 23:24:55 +01:00
/*
* Verify a signature using a public key .
*/
2016-02-02 10:08:53 -08:00
int public_key_verify_signature ( const struct public_key * pkey ,
2013-08-30 16:15:30 +01:00
const struct public_key_signature * sig )
2012-09-21 23:24:55 +01:00
{
2016-03-03 21:49:27 +00:00
struct public_key_completion compl ;
struct crypto_akcipher * tfm ;
struct akcipher_request * req ;
struct scatterlist sig_sg , digest_sg ;
const char * alg_name ;
char alg_name_buf [ CRYPTO_MAX_ALG_NAME ] ;
void * output ;
unsigned int outlen ;
int ret = - ENOMEM ;
pr_devel ( " ==>%s() \n " , __func__ ) ;
2016-02-02 10:08:53 -08:00
BUG_ON ( ! pkey ) ;
2013-08-30 16:15:30 +01:00
BUG_ON ( ! sig ) ;
BUG_ON ( ! sig - > digest ) ;
2016-02-02 10:08:53 -08:00
BUG_ON ( ! sig - > s ) ;
2012-09-21 23:24:55 +01:00
2016-03-03 21:49:27 +00:00
alg_name = sig - > pkey_algo ;
if ( strcmp ( sig - > pkey_algo , " rsa " ) = = 0 ) {
2016-03-03 21:49:27 +00:00
/* The data wangled by the RSA algorithm is typically padded
* and encoded in some manner , such as EMSA - PKCS1 - 1 _5 [ RFC3447
* sec 8.2 ] .
*/
if ( snprintf ( alg_name_buf , CRYPTO_MAX_ALG_NAME ,
2016-03-03 21:49:27 +00:00
" pkcs1pad(rsa,%s) " , sig - > hash_algo
2016-03-03 21:49:27 +00:00
) > = CRYPTO_MAX_ALG_NAME )
return - EINVAL ;
alg_name = alg_name_buf ;
}
tfm = crypto_alloc_akcipher ( alg_name , 0 , 0 ) ;
if ( IS_ERR ( tfm ) )
return PTR_ERR ( tfm ) ;
req = akcipher_request_alloc ( tfm , GFP_KERNEL ) ;
if ( ! req )
goto error_free_tfm ;
ret = crypto_akcipher_set_pub_key ( tfm , pkey - > key , pkey - > keylen ) ;
if ( ret )
goto error_free_req ;
outlen = crypto_akcipher_maxsize ( tfm ) ;
output = kmalloc ( outlen , GFP_KERNEL ) ;
if ( ! output )
goto error_free_req ;
sg_init_one ( & sig_sg , sig - > s , sig - > s_size ) ;
sg_init_one ( & digest_sg , output , outlen ) ;
akcipher_request_set_crypt ( req , & sig_sg , & digest_sg , sig - > s_size ,
outlen ) ;
init_completion ( & compl . completion ) ;
akcipher_request_set_callback ( req , CRYPTO_TFM_REQ_MAY_BACKLOG |
CRYPTO_TFM_REQ_MAY_SLEEP ,
public_key_verify_done , & compl ) ;
/* Perform the verification calculation. This doesn't actually do the
* verification , but rather calculates the hash expected by the
* signature and returns that to us .
*/
ret = crypto_akcipher_verify ( req ) ;
if ( ret = = - EINPROGRESS ) {
wait_for_completion ( & compl . completion ) ;
ret = compl . err ;
}
if ( ret < 0 )
goto out_free_output ;
2012-09-21 23:24:55 +01:00
2016-03-03 21:49:27 +00:00
/* Do the actual verification step. */
if ( req - > dst_len ! = sig - > digest_size | |
memcmp ( sig - > digest , output , sig - > digest_size ) ! = 0 )
ret = - EKEYREJECTED ;
2012-09-21 23:24:55 +01:00
2016-03-03 21:49:27 +00:00
out_free_output :
kfree ( output ) ;
error_free_req :
akcipher_request_free ( req ) ;
error_free_tfm :
crypto_free_akcipher ( tfm ) ;
pr_devel ( " <==%s() = %d \n " , __func__ , ret ) ;
return ret ;
2013-08-30 16:15:30 +01:00
}
EXPORT_SYMBOL_GPL ( public_key_verify_signature ) ;
static int public_key_verify_signature_2 ( const struct key * key ,
const struct public_key_signature * sig )
{
2015-10-21 14:04:48 +01:00
const struct public_key * pk = key - > payload . data [ asym_crypto ] ;
2013-08-30 16:15:30 +01:00
return public_key_verify_signature ( pk , sig ) ;
2012-09-21 23:24:55 +01:00
}
/*
* Public key algorithm asymmetric key subtype
*/
struct asymmetric_key_subtype public_key_subtype = {
. owner = THIS_MODULE ,
. name = " public_key " ,
2014-09-02 13:52:10 +01:00
. name_len = sizeof ( " public_key " ) - 1 ,
2012-09-21 23:24:55 +01:00
. describe = public_key_describe ,
. destroy = public_key_destroy ,
2013-08-30 16:15:30 +01:00
. verify_signature = public_key_verify_signature_2 ,
2012-09-21 23:24:55 +01:00
} ;
EXPORT_SYMBOL_GPL ( public_key_subtype ) ;