@ -341,10 +341,326 @@ int fit_image_add_verification_data(const char *keydir, void *keydest,
return 0 ;
}
struct strlist {
int count ;
char * * strings ;
} ;
static void strlist_init ( struct strlist * list )
{
memset ( list , ' \0 ' , sizeof ( * list ) ) ;
}
static void strlist_free ( struct strlist * list )
{
int i ;
for ( i = 0 ; i < list - > count ; i + + )
free ( list - > strings [ i ] ) ;
free ( list - > strings ) ;
}
static int strlist_add ( struct strlist * list , const char * str )
{
char * dup ;
dup = strdup ( str ) ;
list - > strings = realloc ( list - > strings ,
( list - > count + 1 ) * sizeof ( char * ) ) ;
if ( ! list | | ! str )
return - 1 ;
list - > strings [ list - > count + + ] = dup ;
return 0 ;
}
static const char * fit_config_get_image_list ( void * fit , int noffset ,
int * lenp , int * allow_missingp )
{
static const char default_list [ ] = FIT_KERNEL_PROP " \0 "
FIT_FDT_PROP ;
const char * prop ;
/* If there is an "image" property, use that */
prop = fdt_getprop ( fit , noffset , " sign-images " , lenp ) ;
if ( prop ) {
* allow_missingp = 0 ;
return * lenp ? prop : NULL ;
}
/* Default image list */
* allow_missingp = 1 ;
* lenp = sizeof ( default_list ) ;
return default_list ;
}
static int fit_config_get_hash_list ( void * fit , int conf_noffset ,
int sig_offset , struct strlist * node_inc )
{
int allow_missing ;
const char * prop , * iname , * end ;
const char * conf_name , * sig_name ;
char name [ 200 ] , path [ 200 ] ;
int image_count ;
int ret , len ;
conf_name = fit_get_name ( fit , conf_noffset , NULL ) ;
sig_name = fit_get_name ( fit , sig_offset , NULL ) ;
/*
* Build a list of nodes we need to hash . We always need the root
* node and the configuration .
*/
strlist_init ( node_inc ) ;
snprintf ( name , sizeof ( name ) , " %s/%s " , FIT_CONFS_PATH , conf_name ) ;
if ( strlist_add ( node_inc , " / " ) | |
strlist_add ( node_inc , name ) )
goto err_mem ;
/* Get a list of images that we intend to sign */
prop = fit_config_get_image_list ( fit , conf_noffset , & len ,
& allow_missing ) ;
if ( ! prop )
return 0 ;
/* Locate the images */
end = prop + len ;
image_count = 0 ;
for ( iname = prop ; iname < end ; iname + = strlen ( iname ) + 1 ) {
int noffset ;
int image_noffset ;
int hash_count ;
image_noffset = fit_conf_get_prop_node ( fit , conf_noffset ,
iname ) ;
if ( image_noffset < 0 ) {
printf ( " Failed to find image '%s' in configuration '%s/%s' \n " ,
iname , conf_name , sig_name ) ;
if ( allow_missing )
continue ;
return - ENOENT ;
}
ret = fdt_get_path ( fit , image_noffset , path , sizeof ( path ) ) ;
if ( ret < 0 )
goto err_path ;
if ( strlist_add ( node_inc , path ) )
goto err_mem ;
snprintf ( name , sizeof ( name ) , " %s/%s " , FIT_CONFS_PATH ,
conf_name ) ;
/* Add all this image's hashes */
hash_count = 0 ;
for ( noffset = fdt_first_subnode ( fit , image_noffset ) ;
noffset > = 0 ;
noffset = fdt_next_subnode ( fit , noffset ) ) {
const char * name = fit_get_name ( fit , noffset , NULL ) ;
if ( strncmp ( name , FIT_HASH_NODENAME ,
strlen ( FIT_HASH_NODENAME ) ) )
continue ;
ret = fdt_get_path ( fit , noffset , path , sizeof ( path ) ) ;
if ( ret < 0 )
goto err_path ;
if ( strlist_add ( node_inc , path ) )
goto err_mem ;
hash_count + + ;
}
if ( ! hash_count ) {
printf ( " Failed to find any hash nodes in configuration '%s/%s' image '%s' - without these it is not possible to verify this image \n " ,
conf_name , sig_name , iname ) ;
return - ENOMSG ;
}
image_count + + ;
}
if ( ! image_count ) {
printf ( " Failed to find any images for configuration '%s/%s' \n " ,
conf_name , sig_name ) ;
return - ENOMSG ;
}
return 0 ;
err_mem :
printf ( " Out of memory processing configuration '%s/%s' \n " , conf_name ,
sig_name ) ;
return - ENOMEM ;
err_path :
printf ( " Failed to get path for image '%s' in configuration '%s/%s': %s \n " ,
iname , conf_name , sig_name , fdt_strerror ( ret ) ) ;
return - ENOENT ;
}
static int fit_config_get_data ( void * fit , int conf_noffset , int noffset ,
struct image_region * * regionp , int * region_countp ,
char * * region_propp , int * region_proplen )
{
char * const exc_prop [ ] = { " data " } ;
struct strlist node_inc ;
struct image_region * region ;
struct fdt_region fdt_regions [ 100 ] ;
const char * conf_name , * sig_name ;
char path [ 200 ] ;
int count , i ;
char * region_prop ;
int ret , len ;
conf_name = fit_get_name ( fit , conf_noffset , NULL ) ;
sig_name = fit_get_name ( fit , conf_noffset , NULL ) ;
debug ( " %s: conf='%s', sig='%s' \n " , __func__ , conf_name , sig_name ) ;
/* Get a list of nodes we want to hash */
ret = fit_config_get_hash_list ( fit , conf_noffset , noffset , & node_inc ) ;
if ( ret )
return ret ;
/* Get a list of regions to hash */
count = fdt_find_regions ( fit , node_inc . strings , node_inc . count ,
exc_prop , ARRAY_SIZE ( exc_prop ) ,
fdt_regions , ARRAY_SIZE ( fdt_regions ) ,
path , sizeof ( path ) , 1 ) ;
if ( count < 0 ) {
printf ( " Failed to hash configuration '%s/%s': %s \n " , conf_name ,
sig_name , fdt_strerror ( ret ) ) ;
return - EIO ;
}
if ( count = = 0 ) {
printf ( " No data to hash for configuration '%s/%s': %s \n " ,
conf_name , sig_name , fdt_strerror ( ret ) ) ;
return - EINVAL ;
}
/* Build our list of data blocks */
region = fit_region_make_list ( fit , fdt_regions , count , NULL ) ;
if ( ! region ) {
printf ( " Out of memory hashing configuration '%s/%s' \n " ,
conf_name , sig_name ) ;
return - ENOMEM ;
}
/* Create a list of all hashed properties */
debug ( " Hash nodes: \n " ) ;
for ( i = len = 0 ; i < node_inc . count ; i + + ) {
debug ( " %s \n " , node_inc . strings [ i ] ) ;
len + = strlen ( node_inc . strings [ i ] ) + 1 ;
}
region_prop = malloc ( len ) ;
if ( ! region_prop ) {
printf ( " Out of memory setting up regions for configuration '%s/%s' \n " ,
conf_name , sig_name ) ;
return - ENOMEM ;
}
for ( i = len = 0 ; i < node_inc . count ;
len + = strlen ( node_inc . strings [ i ] ) + 1 , i + + )
strcpy ( region_prop + len , node_inc . strings [ i ] ) ;
strlist_free ( & node_inc ) ;
* region_countp = count ;
* regionp = region ;
* region_propp = region_prop ;
* region_proplen = len ;
return 0 ;
}
static int fit_config_process_sig ( const char * keydir , void * keydest ,
void * fit , const char * conf_name , int conf_noffset ,
int noffset , const char * comment , int require_keys )
{
struct image_sign_info info ;
const char * node_name ;
struct image_region * region ;
char * region_prop ;
int region_proplen ;
int region_count ;
uint8_t * value ;
uint value_len ;
int ret ;
node_name = fit_get_name ( fit , noffset , NULL ) ;
if ( fit_config_get_data ( fit , conf_noffset , noffset , & region ,
& region_count , & region_prop , & region_proplen ) )
return - 1 ;
if ( fit_image_setup_sig ( & info , keydir , fit , conf_name , noffset ,
require_keys ? " conf " : NULL ) )
return - 1 ;
ret = info . algo - > sign ( & info , region , region_count , & value , & value_len ) ;
free ( region ) ;
if ( ret ) {
printf ( " Failed to sign '%s' signature node in '%s' conf node \n " ,
node_name , conf_name ) ;
/* We allow keys to be missing */
if ( ret = = - ENOENT )
return 0 ;
return - 1 ;
}
if ( fit_image_write_sig ( fit , noffset , value , value_len , comment ,
region_prop , region_proplen ) ) {
printf ( " Can't write signature for '%s' signature node in '%s' conf node \n " ,
node_name , conf_name ) ;
return - 1 ;
}
free ( value ) ;
free ( region_prop ) ;
/* Get keyname again, as FDT has changed and invalidated our pointer */
info . keyname = fdt_getprop ( fit , noffset , " key-name-hint " , NULL ) ;
/* Write the public key into the supplied FDT file */
if ( keydest & & info . algo - > add_verify_data ( & info , keydest ) ) {
printf ( " Failed to add verification data for '%s' signature node in '%s' image node \n " ,
node_name , conf_name ) ;
return - 1 ;
}
return 0 ;
}
static int fit_config_add_verification_data ( const char * keydir , void * keydest ,
void * fit , int conf_noffset , const char * comment ,
int require_keys )
{
const char * conf_name ;
int noffset ;
conf_name = fit_get_name ( fit , conf_noffset , NULL ) ;
/* Process all hash subnodes of the configuration node */
for ( noffset = fdt_first_subnode ( fit , conf_noffset ) ;
noffset > = 0 ;
noffset = fdt_next_subnode ( fit , noffset ) ) {
const char * node_name ;
int ret = 0 ;
node_name = fit_get_name ( fit , noffset , NULL ) ;
if ( ! strncmp ( node_name , FIT_SIG_NODENAME ,
strlen ( FIT_SIG_NODENAME ) ) ) {
ret = fit_config_process_sig ( keydir , keydest ,
fit , conf_name , conf_noffset , noffset , comment ,
require_keys ) ;
}
if ( ret )
return ret ;
}
return 0 ;
}
int fit_add_verification_data ( const char * keydir , void * keydest , void * fit ,
const char * comment , int require_keys )
{
int images_noffset ;
int images_noffset , confs_noffset ;
int noffset ;
int ret ;
@ -370,5 +686,28 @@ int fit_add_verification_data(const char *keydir, void *keydest, void *fit,
return ret ;
}
/* If there are no keys, we can't sign configurations */
if ( ! IMAGE_ENABLE_SIGN | | ! keydir )
return 0 ;
/* Find configurations parent node offset */
confs_noffset = fdt_path_offset ( fit , FIT_CONFS_PATH ) ;
if ( confs_noffset < 0 ) {
printf ( " Can't find images parent node '%s' (%s) \n " ,
FIT_IMAGES_PATH , fdt_strerror ( confs_noffset ) ) ;
return - ENOENT ;
}
/* Process its subnodes, print out component images details */
for ( noffset = fdt_first_subnode ( fit , confs_noffset ) ;
noffset > = 0 ;
noffset = fdt_next_subnode ( fit , noffset ) ) {
ret = fit_config_add_verification_data ( keydir , keydest ,
fit , noffset , comment ,
require_keys ) ;
if ( ret )
return ret ;
}
return 0 ;
}