2013-02-07 02:12:08 +04:00
/*
* Copyright ( C ) 2013 Intel Corporation
*
* Author :
* Dmitry Kasatkin < dmitry . kasatkin @ intel . 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 , version 2 of the License .
*
*/
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
# include <linux/err.h>
2014-07-02 16:12:26 +04:00
# include <linux/ratelimit.h>
2013-02-07 02:12:08 +04:00
# include <linux/key-type.h>
# include <crypto/public_key.h>
2016-03-04 00:49:27 +03:00
# include <crypto/hash_info.h>
2013-02-07 02:12:08 +04:00
# include <keys/asymmetric-type.h>
2015-12-02 18:47:55 +03:00
# include <keys/system_keyring.h>
2013-02-07 02:12:08 +04:00
# include "integrity.h"
/*
* Request an asymmetric key .
*/
static struct key * request_asymmetric_key ( struct key * keyring , uint32_t keyid )
{
struct key * key ;
char name [ 12 ] ;
2014-10-06 20:31:58 +04:00
sprintf ( name , " id:%08x " , keyid ) ;
2013-02-07 02:12:08 +04:00
pr_debug ( " key search: \" %s \" \n " , name ) ;
2015-12-02 18:47:55 +03:00
key = get_ima_blacklist_keyring ( ) ;
if ( key ) {
key_ref_t kref ;
kref = keyring_search ( make_key_ref ( key , 1 ) ,
& key_type_asymmetric , name ) ;
if ( ! IS_ERR ( kref ) ) {
pr_err ( " Key '%s' is in ima_blacklist_keyring \n " , name ) ;
return ERR_PTR ( - EKEYREJECTED ) ;
}
}
2013-02-07 02:12:08 +04:00
if ( keyring ) {
/* search in specific keyring */
key_ref_t kref ;
2015-12-02 18:47:55 +03:00
2013-02-07 02:12:08 +04:00
kref = keyring_search ( make_key_ref ( keyring , 1 ) ,
& key_type_asymmetric , name ) ;
if ( IS_ERR ( kref ) )
key = ERR_CAST ( kref ) ;
else
key = key_ref_to_ptr ( kref ) ;
} else {
key = request_key ( & key_type_asymmetric , name , NULL ) ;
}
if ( IS_ERR ( key ) ) {
2014-07-02 16:12:26 +04:00
pr_err_ratelimited ( " Request for unknown key '%s' err %ld \n " ,
name , PTR_ERR ( key ) ) ;
2013-02-07 02:12:08 +04:00
switch ( PTR_ERR ( key ) ) {
/* Hide some search errors */
case - EACCES :
case - ENOTDIR :
case - EAGAIN :
return ERR_PTR ( - ENOKEY ) ;
default :
return key ;
}
}
pr_debug ( " %s() = 0 [%x] \n " , __func__ , key_serial ( key ) ) ;
return key ;
}
int asymmetric_verify ( struct key * keyring , const char * sig ,
int siglen , const char * data , int datalen )
{
struct public_key_signature pks ;
struct signature_v2_hdr * hdr = ( struct signature_v2_hdr * ) sig ;
struct key * key ;
int ret = - ENOMEM ;
if ( siglen < = sizeof ( * hdr ) )
return - EBADMSG ;
siglen - = sizeof ( * hdr ) ;
2017-06-08 04:49:10 +03:00
if ( siglen ! = be16_to_cpu ( hdr - > sig_size ) )
2013-02-07 02:12:08 +04:00
return - EBADMSG ;
2016-03-04 00:49:27 +03:00
if ( hdr - > hash_algo > = HASH_ALGO__LAST )
2013-02-07 02:12:08 +04:00
return - ENOPKG ;
2017-06-08 04:49:10 +03:00
key = request_asymmetric_key ( keyring , be32_to_cpu ( hdr - > keyid ) ) ;
2013-02-07 02:12:08 +04:00
if ( IS_ERR ( key ) )
return PTR_ERR ( key ) ;
memset ( & pks , 0 , sizeof ( pks ) ) ;
2016-03-04 00:49:27 +03:00
pks . pkey_algo = " rsa " ;
pks . hash_algo = hash_algo_name [ hdr - > hash_algo ] ;
2013-02-07 02:12:08 +04:00
pks . digest = ( u8 * ) data ;
pks . digest_size = datalen ;
2016-02-02 21:08:58 +03:00
pks . s = hdr - > sig ;
pks . s_size = siglen ;
ret = verify_signature ( key , & pks ) ;
2013-02-07 02:12:08 +04:00
key_put ( key ) ;
pr_debug ( " %s() = %d \n " , __func__ , ret ) ;
return ret ;
}