2019-06-27 23:19:28 -03:00
// SPDX-License-Identifier: GPL-2.0+
/*
* IMA support for appraising module - style appended signatures .
*
* Copyright ( C ) 2019 IBM Corporation
*
* Author :
* Thiago Jung Bauermann < bauerman @ linux . ibm . com >
*/
2019-06-27 23:19:30 -03:00
# include <linux/types.h>
# include <linux/module_signature.h>
# include <keys/asymmetric-type.h>
# include <crypto/pkcs7.h>
2019-06-27 23:19:28 -03:00
# include "ima.h"
2019-06-27 23:19:30 -03:00
struct modsig {
struct pkcs7_message * pkcs7_msg ;
2019-06-27 23:19:31 -03:00
enum hash_algo hash_algo ;
/* This digest will go in the 'd-modsig' field of the IMA template. */
const u8 * digest ;
u32 digest_size ;
/*
* This is what will go to the measurement list if the template requires
* storing the signature .
*/
int raw_pkcs7_len ;
u8 raw_pkcs7 [ ] ;
2019-06-27 23:19:30 -03:00
} ;
/*
* ima_read_modsig - Read modsig from buf .
*
* Return : 0 on success , error code otherwise .
*/
int ima_read_modsig ( enum ima_hooks func , const void * buf , loff_t buf_len ,
struct modsig * * modsig )
{
const size_t marker_len = strlen ( MODULE_SIG_STRING ) ;
const struct module_signature * sig ;
struct modsig * hdr ;
size_t sig_len ;
const void * p ;
int rc ;
if ( buf_len < = marker_len + sizeof ( * sig ) )
return - ENOENT ;
p = buf + buf_len - marker_len ;
if ( memcmp ( p , MODULE_SIG_STRING , marker_len ) )
return - ENOENT ;
buf_len - = marker_len ;
sig = ( const struct module_signature * ) ( p - sizeof ( * sig ) ) ;
rc = mod_check_sig ( sig , buf_len , func_tokens [ func ] ) ;
if ( rc )
return rc ;
sig_len = be32_to_cpu ( sig - > sig_len ) ;
buf_len - = sig_len + sizeof ( * sig ) ;
2019-06-27 23:19:31 -03:00
/* Allocate sig_len additional bytes to hold the raw PKCS#7 data. */
hdr = kzalloc ( sizeof ( * hdr ) + sig_len , GFP_KERNEL ) ;
2019-06-27 23:19:30 -03:00
if ( ! hdr )
return - ENOMEM ;
hdr - > pkcs7_msg = pkcs7_parse_message ( buf + buf_len , sig_len ) ;
if ( IS_ERR ( hdr - > pkcs7_msg ) ) {
2019-08-07 21:43:18 -03:00
rc = PTR_ERR ( hdr - > pkcs7_msg ) ;
2019-06-27 23:19:30 -03:00
kfree ( hdr ) ;
2019-08-07 21:43:18 -03:00
return rc ;
2019-06-27 23:19:30 -03:00
}
2019-06-27 23:19:31 -03:00
memcpy ( hdr - > raw_pkcs7 , buf + buf_len , sig_len ) ;
hdr - > raw_pkcs7_len = sig_len ;
/* We don't know the hash algorithm yet. */
hdr - > hash_algo = HASH_ALGO__LAST ;
2019-06-27 23:19:30 -03:00
* modsig = hdr ;
return 0 ;
}
2019-06-27 23:19:31 -03:00
/**
* ima_collect_modsig - Calculate the file hash without the appended signature .
*
* Since the modsig is part of the file contents , the hash used in its signature
* isn ' t the same one ordinarily calculated by IMA . Therefore PKCS7 code
* calculates a separate one for signature verification .
*/
void ima_collect_modsig ( struct modsig * modsig , const void * buf , loff_t size )
{
int rc ;
/*
* Provide the file contents ( minus the appended sig ) so that the PKCS7
* code can calculate the file hash .
*/
size - = modsig - > raw_pkcs7_len + strlen ( MODULE_SIG_STRING ) +
sizeof ( struct module_signature ) ;
rc = pkcs7_supply_detached_data ( modsig - > pkcs7_msg , buf , size ) ;
if ( rc )
return ;
/* Ask the PKCS7 code to calculate the file hash. */
rc = pkcs7_get_digest ( modsig - > pkcs7_msg , & modsig - > digest ,
& modsig - > digest_size , & modsig - > hash_algo ) ;
}
2019-06-27 23:19:30 -03:00
int ima_modsig_verify ( struct key * keyring , const struct modsig * modsig )
{
return verify_pkcs7_message_sig ( NULL , 0 , modsig - > pkcs7_msg , keyring ,
VERIFYING_MODULE_SIGNATURE , NULL , NULL ) ;
}
2019-06-27 23:19:32 -03:00
int ima_get_modsig_digest ( const struct modsig * modsig , enum hash_algo * algo ,
const u8 * * digest , u32 * digest_size )
{
* algo = modsig - > hash_algo ;
* digest = modsig - > digest ;
* digest_size = modsig - > digest_size ;
return 0 ;
}
int ima_get_raw_modsig ( const struct modsig * modsig , const void * * data ,
u32 * data_len )
{
* data = & modsig - > raw_pkcs7 ;
* data_len = modsig - > raw_pkcs7_len ;
return 0 ;
}
2019-06-27 23:19:30 -03:00
void ima_free_modsig ( struct modsig * modsig )
{
if ( ! modsig )
return ;
pkcs7_free_message ( modsig - > pkcs7_msg ) ;
kfree ( modsig ) ;
}