mirror of
https://github.com/gnuton/asuswrt-merlin.ng.git
synced 2025-05-19 16:02:36 +02:00
354 lines
12 KiB
Perl
Executable file
354 lines
12 KiB
Perl
Executable file
#!/usr/bin/env perl
|
|
use strict;
|
|
use warnings;
|
|
use bytes;
|
|
use Data::Dumper;
|
|
####
|
|
#### Assembles images for GEN3 devices with puresqubi ONLY;
|
|
#### Includes MFG images and TK keystore
|
|
####
|
|
unless ( $ENV{SECURE_BOOT_ARCH} eq 'GEN3' ) {
|
|
die "Not supported $ENV{SECURE_BOOT_ARCH}";
|
|
}
|
|
|
|
sub shell {
|
|
|
|
#if (defined $_[1]) {
|
|
print "$_[0]\n";
|
|
|
|
#}
|
|
my $res = `$_[0]`;
|
|
( $? == 0 ) or die "ERROR: $!";
|
|
print "$res";
|
|
return $res;
|
|
}
|
|
my $_IMGS="";
|
|
if ($ENV{OTHER_IMAGES}) {
|
|
$_IMGS = $ENV{OTHER_IMAGES};
|
|
}
|
|
my $HASHES_OPT =
|
|
(defined $ENV{encrypt} && $ENV{encrypt} eq '2') ?
|
|
'--encrypted --compressed' : '';
|
|
#
|
|
# print Dumper(\%ENV);
|
|
|
|
|
|
#
|
|
# Staging of the script
|
|
#
|
|
# Stage 1: prepare - generates authenticated headers and hashes, prepares non-secure cferom then exit
|
|
# !!! must be complete by stage 2
|
|
#
|
|
# Stage 2: complete - expects hashes/headers/bootloader signatures generated outside of the scope of this script
|
|
# before this stage is executed
|
|
#
|
|
|
|
print "-- args @ARGV --- \n";
|
|
|
|
my @args = @ARGV;
|
|
|
|
my $max_image_size = $ENV{BTRM_IMAGE_SIZE_ALLOCATION} * 1024;
|
|
#
|
|
# max nvram size
|
|
my $nvram_size = 1024;
|
|
#
|
|
# max nvrams
|
|
# 2 of 3 in at least in 2 different erase blocks
|
|
# 2 of 2 could be in the same block
|
|
# more nvram instances can be added; modiry nvram_offset array accordingly
|
|
my $num_nvram = 3;
|
|
#
|
|
#accounting for dupilcate NVRAM block
|
|
# NVRAM size is set at 1024
|
|
my $image_alloc_size = $max_image_size + $nvram_size;
|
|
#
|
|
# starting offset where first image is placed
|
|
my $offset = 65536;
|
|
#
|
|
# number of unsecured images:
|
|
# 2 copies of unsec images + one headerless XIP cferom
|
|
my $num_unsec_images = 3;
|
|
#
|
|
# 2 copies of fld secure images
|
|
my $num_sec_images = 2;
|
|
|
|
#
|
|
# we want to insert secure+unsecure images in 1MB
|
|
# let's guard against overflow
|
|
# account for 65k reserved block from the beginning of the boot area
|
|
( ((1024*1024 - $offset) - ($image_alloc_size * ($num_unsec_images + $num_sec_images)) - ($nvram_size*$num_nvram)) >= 0 )
|
|
or die "this number of images will not fit to a boot area";
|
|
|
|
#
|
|
# prepare an array of offsets for non-secure images
|
|
#
|
|
my @unsec_offset = map{ $offset + $image_alloc_size * $_} (0..$num_unsec_images-1);
|
|
|
|
$offset = $unsec_offset[-1] + $image_alloc_size;
|
|
#
|
|
# set an array of offsets for secure images
|
|
#
|
|
my @sec_offset = map{ $offset + $image_alloc_size * $_} (0..$num_sec_images-1);
|
|
|
|
#
|
|
# transforms string NAND BLOCKSIZEs in Kilo denominations to a sorted array of numeral perl representation
|
|
my @block_size = sort map{ $_ * 1024 } (split(' ',$ENV{BUILD_NAND_IMG_BLKSIZE}));
|
|
#
|
|
# prepare NVRAM offset list arranging it be place
|
|
# place nvram instance at least in 2 different erase blocks
|
|
# The loop below places in 2 different blocks
|
|
my $nvram_offs;
|
|
foreach (@unsec_offset,@sec_offset) {
|
|
my $sz = $_ + $image_alloc_size;
|
|
if ( $sz <= $block_size[-1]) {
|
|
if ($num_nvram > 1 ) {
|
|
$nvram_offs .= ($sz - $nvram_size) . ",";
|
|
$num_nvram--;
|
|
}
|
|
} else {
|
|
if ($num_nvram > 0) {
|
|
$nvram_offs .= ($sz - $nvram_size) . ",";
|
|
$num_nvram--;
|
|
}
|
|
}
|
|
}
|
|
# if num_nvram still non zero assume that nvram were set
|
|
# in one block; forcing at least in the next block
|
|
if ($num_nvram) {
|
|
$nvram_offs .= $block_size[-1] ;
|
|
}
|
|
#
|
|
### IF YOU WANT CUSTOM OFFSETS, replace values in @unsec_offset, @sec_offset and @nvram_offs
|
|
#
|
|
print " nvram offsets: $nvram_offs \n unsecure images offsets : @unsec_offset \n secure images offsets: @sec_offset \n nand erase blocks @block_size\n";
|
|
#
|
|
# Re-assigning to a local variable to take into account
|
|
# an SOTP TurnKey choice
|
|
#
|
|
#
|
|
my $CFE_ROM = (defined($ENV{SECURE_BOOT_TURNKEY}) && ($ENV{SECURE_BOOT_TURNKEY} eq "y") ) ? $ENV{WDIR}.'/'.$ENV{CFE_ROM_TK_BN} : $ENV{WDIR}.'/'.$ENV{CFE_ROM_BN};
|
|
|
|
if ( !( $ENV{SECURE_BOOT_ENCRYPT_BTLDRS} eq 'y' ) ) {
|
|
$ENV{MFG_ENC} = '';
|
|
$ENV{FLD_ENC} = '';
|
|
}
|
|
|
|
if ( ( defined $args[0] ) && ($args[0] eq "prepare") ) {
|
|
if ( $ENV{BUILD_SECURE_BOOT} eq 'y' ) {
|
|
|
|
#
|
|
#
|
|
# Create the block of hashes
|
|
|
|
shell(
|
|
"$ENV{HOSTTOOLS_DIR}/imagetools/mkhashes \\
|
|
--out=$ENV{WDIR}/.hashes.fld --item rootfs=$ENV{PROFILE_DIR}/squashfs.img --file secram.000 --boot $ENV{WDIR}/bootfs $HASHES_OPT"
|
|
);
|
|
|
|
#
|
|
# Generate the MFG auth headers for CFEROM
|
|
shell(
|
|
"$ENV{HOSTTOOLS_DIR}/imagetools/insertboot --arch $ENV{SECURE_BOOT_ARCH} --cfe $CFE_ROM$ENV{MFG_ENC} \\
|
|
--mfg --cred=$ENV{MFG_CRED_LIST} --chip=$ENV{BRCM_CHIP} --out=$ENV{WDIR}/.header.mfg"
|
|
);
|
|
|
|
#
|
|
#
|
|
# Create the block of hashes
|
|
shell(
|
|
"$ENV{HOSTTOOLS_DIR}/imagetools/mkhashes \\
|
|
--out=$ENV{WDIR}/.hashes.mfg --item rootfs=$ENV{PROFILE_DIR}/squashfs.img --file secmfg.000 --boot $ENV{WDIR}/bootfs $HASHES_OPT"
|
|
);
|
|
|
|
#
|
|
# Generate the FLD auth headers for CFEROM
|
|
shell(
|
|
# adding original non-tk capable CFE_ROM
|
|
"$ENV{HOSTTOOLS_DIR}/imagetools/insertboot --arch $ENV{SECURE_BOOT_ARCH} --cfe $ENV{WDIR}/$ENV{CFE_ROM_BN}$ENV{FLD_ENC} \\
|
|
--field --cred=$ENV{FLD_CRED_LIST} --chip=$ENV{BRCM_CHIP} --out=$ENV{WDIR}/.header.fld"
|
|
);
|
|
|
|
if ( defined($ENV{SECURE_BOOT_TURNKEY}) && ($ENV{SECURE_BOOT_TURNKEY} eq "y") ) {
|
|
if ( $ENV{SECURE_BOOT_TK_MODE_REQ} eq "FLD" ) {
|
|
shell(
|
|
"$ENV{HOSTTOOLS_DIR}/SecureBootUtils/genkeyst $ENV{KEYSTORE_ARGS} --args keyinfo=$ENV{WDIR}/keyinf \\
|
|
--args ek=$ENV{WDIR}/FLD_EK.enc --args iv=$ENV{WDIR}/FLD_IV.enc --args hash=$ENV{TK_FLD_HASH} \\
|
|
--args mid=$ENV{SECURE_BOOT_TK_MID}"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
print "$0 Executed $args[0] stage\n";
|
|
exit 0;
|
|
}
|
|
|
|
# Building
|
|
# Non-secure and/or FLd secure image
|
|
#
|
|
# This demonstrates how to finalize an image. Here, one would insert any additional components to be included
|
|
# in the signature block for the boot filesystem
|
|
# Create the block of hashes
|
|
shell(
|
|
"$ENV{HOSTTOOLS_DIR}/imagetools/mkhashes \\
|
|
--out=$ENV{WDIR}/hashes.bin --item rootfs=$ENV{PROFILE_DIR}/squashfs.img --file cferam.000 --boot $ENV{WDIR}/bootfs"
|
|
);
|
|
|
|
#
|
|
# Get rid of the non-hash signature
|
|
shell("rm -f $ENV{WDIR}/bootfs/vmlinux.sig");
|
|
|
|
#
|
|
#
|
|
#
|
|
# build UBI cferom
|
|
#
|
|
# start with a 1meg empty region
|
|
shell("$ENV{HOSTTOOLS_DIR}/imagetools/gen1meg $ENV{WDIR}/region");
|
|
|
|
#
|
|
# insert a few copies of an essentially empty nvram
|
|
# prepare NVRAM offset list
|
|
shell(
|
|
"$ENV{HOSTTOOLS_DIR}/createimg.pl --replace --offsets=$nvram_offs --input=$ENV{WDIR}/region --outputfile=$ENV{WDIR}/region \\
|
|
--nvram_magic --conf $ENV{HOSTTOOLS_DIR}/local_install/conf/$ENV{TOOLCHAIN_PREFIX}.conf"
|
|
);
|
|
|
|
#
|
|
#
|
|
# and put a few copies of cferom in flash with nonsecure headers; add one XIP image
|
|
# $offset == 65536;
|
|
#
|
|
foreach (@unsec_offset) {
|
|
if ($_ == 0) {
|
|
shell(
|
|
"$ENV{HOSTTOOLS_DIR}/imagetools/insertboot --cfe $ENV{CFE_ROM}$_IMGS --arch XIP \\
|
|
--chip=$ENV{BRCM_CHIP} --offset $_ $ENV{WDIR}/region"
|
|
);
|
|
} else {
|
|
shell(
|
|
"$ENV{HOSTTOOLS_DIR}/imagetools/insertboot --arch $ENV{SECURE_BOOT_ARCH} --cfe $CFE_ROM$_IMGS --nonsec \\
|
|
--chip=$ENV{BRCM_CHIP} --offset $_ $ENV{WDIR}/region"
|
|
);
|
|
}
|
|
}
|
|
|
|
if ( defined ($ENV{BUILD_SECURE_BOOT}) && ($ENV{BUILD_SECURE_BOOT} eq 'y') ) {
|
|
|
|
# For every openssl call in this script there is an opportunity to replace it with a call to a remote server, HSM or web portal
|
|
# In such case it is assumed that header hashes or will be sent and returned sign to resume image assemble
|
|
#
|
|
# Below is a local openssl implementaion
|
|
#
|
|
|
|
shell(
|
|
"cat $ENV{WDIR}/.hashes.mfg.sig $ENV{WDIR}/.hashes.mfg > $ENV{WDIR}/hashes.mfg"
|
|
);
|
|
|
|
|
|
#
|
|
# insert 1 copy of the MFG or FLD signed cferom into flash image
|
|
shell(
|
|
"$ENV{HOSTTOOLS_DIR}/imagetools/insertboot --arch $ENV{SECURE_BOOT_ARCH} --cfe $CFE_ROM$ENV{MFG_ENC}$_IMGS --mfg=$ENV{WDIR}/.auth.header.mfg.sig \\
|
|
--cred=$ENV{MFG_CRED_LIST} --chip=$ENV{BRCM_CHIP} --offset $sec_offset[0] $ENV{WDIR}/region"
|
|
);
|
|
|
|
shell(
|
|
"cat $ENV{WDIR}/.hashes.fld.sig $ENV{WDIR}/.hashes.fld > $ENV{WDIR}/hashes.fld"
|
|
);
|
|
|
|
#
|
|
# insert 1 copy of the FLD signed cferom into flash image
|
|
shell(
|
|
"$ENV{HOSTTOOLS_DIR}/imagetools/insertboot --arch $ENV{SECURE_BOOT_ARCH} --cfe $ENV{WDIR}/$ENV{CFE_ROM_BN}$ENV{FLD_ENC}$_IMGS --field=$ENV{WDIR}/.auth.header.fld.sig \\
|
|
--cred=$ENV{FLD_CRED_LIST} --chip=$ENV{BRCM_CHIP} --offset $sec_offset[1] $ENV{WDIR}/region"
|
|
);
|
|
|
|
shell("cp -f $ENV{WDIR}/hashes.fld $ENV{WDIR}/hashes.mfg $ENV{WDIR}/bootfs");
|
|
}
|
|
|
|
# insert keystore if configured
|
|
#
|
|
if ( defined($ENV{SECURE_BOOT_TURNKEY}) && ($ENV{SECURE_BOOT_TURNKEY} eq "y") ) {
|
|
if ( $ENV{SECURE_BOOT_TK_MODE_REQ} eq "MFG" ) {
|
|
shell(
|
|
"$ENV{HOSTTOOLS_DIR}/SecureBootUtils/genkeyst $ENV{KEYSTORE_ARGS} --args out=$ENV{WDIR}/keyst.bin"
|
|
);
|
|
}
|
|
elsif ( $ENV{SECURE_BOOT_TK_MODE_REQ} eq "FLD" ) {
|
|
|
|
# At this stage an outside script has encrypted fld keys and had signed keyinfo
|
|
shell("cat $ENV{WDIR}/keyinf.sig $ENV{WDIR}/keyinf > $ENV{WDIR}/keyinf.signed");
|
|
shell(
|
|
"$ENV{HOSTTOOLS_DIR}/SecureBootUtils/genkeyst $ENV{KEYSTORE_ARGS} --args keystore=$ENV{WDIR}/keyinf.signed --args out=$ENV{WDIR}/keyst.bin"
|
|
);
|
|
}
|
|
|
|
#append to boot region @ the offset
|
|
shell(
|
|
"$ENV{HOSTTOOLS_DIR}/SecureBootUtils/utils -optn update=$ENV{WDIR}/region -optn offs=$ENV{SECURE_BOOT_TK_KS_OFFS}K -optn in=$ENV{WDIR}/keyst.bin"
|
|
);
|
|
}
|
|
|
|
|
|
#
|
|
# Copy hashes for Non-Secure, MFG and FLD to bootfs
|
|
shell("cp -f $ENV{WDIR}/hashes.bin $ENV{WDIR}/hashes.mfg $ENV{WDIR}/hashes.fld $ENV{WDIR}/bootfs");
|
|
|
|
#
|
|
# Create the pureubi "blob.bin" file with cferam, vmlinux, dtbs, etc...
|
|
shell(
|
|
"$ENV{HOSTTOOLS_DIR}/imagetools/mkfs.nada --out=$ENV{WDIR}/head/blob.bin $ENV{WDIR}/bootfs"
|
|
);
|
|
|
|
# Then create the metadata for the image
|
|
shell(
|
|
"$ENV{HOSTTOOLS_DIR}/imagetools/mkfs.nada --out=$ENV{WDIR}/head/meta.bin --extra cferam.000=998 --extra squash=1 --extra committed=0"
|
|
);
|
|
|
|
#
|
|
#build_ubi
|
|
#
|
|
# generate a ubi.ini file combining the rootfs, metadata, and boot volumes
|
|
#
|
|
shell(
|
|
"$ENV{HOSTTOOLS_DIR}/imagetools/mkubi_ini --meta=$ENV{WDIR}/head/meta.bin --boot=$ENV{WDIR}/head/blob.bin \\
|
|
--root=$ENV{PROFILE_DIR}/squashfs.img > $ENV{WDIR}/ubi.ini"
|
|
);
|
|
|
|
#
|
|
# iterate over all enabled NAND block sizes
|
|
#
|
|
foreach (@block_size) {
|
|
my $i = $_ /1024;
|
|
print "## Generating ubinized image for NAND $i kb blocksize ##\n";
|
|
my $pg_size = shell("$ENV{HOSTTOOLS_DIR}/imagetools/nand_peb_to_pg_size $i");
|
|
#
|
|
# this is an implicit conversion from string to integer; purpousefully simple
|
|
#
|
|
#my $peb_size = $_;
|
|
print "PEB SIZE $_ \n";
|
|
shell(
|
|
"$ENV{HOSTTOOLS_DIR}/mtd-utils*/ubinize -v -o $ENV{WDIR}/my_rootfs${i}kb_puresqubi.img \\
|
|
-m ${pg_size} -p $_ $ENV{WDIR}/ubi.ini"
|
|
);
|
|
shell(
|
|
"$ENV{HOSTTOOLS_DIR}/addvtoken --endian $ENV{ARCH_ENDIAN} --chip $ENV{BRCM_CHIP} --flashtype NAND$i --btrm 1 \\
|
|
$ENV{WDIR}/my_rootfs${i}kb_puresqubi.img $ENV{WDIR}/custom_$ENV{PROFILE}_puresqubi_${i}.w"
|
|
);
|
|
shell(
|
|
"cat $ENV{WDIR}/region $ENV{WDIR}/my_rootfs${i}kb_puresqubi.img > $ENV{WDIR}/my_cferom_rootfs${i}kb_puresqubi.img"
|
|
);
|
|
shell(
|
|
"$ENV{HOSTTOOLS_DIR}/addvtoken --endian $ENV{ARCH_ENDIAN} --chip $ENV{BRCM_CHIP} --flashtype NAND${i} --btrm 1 \\
|
|
$ENV{IMG_DDR_TYPE_OPT} $ENV{WDIR}/my_cferom_rootfs${i}kb_puresqubi.img $ENV{WDIR}/custom_$ENV{PROFILE}_cferom_puresqubi_${i}.w"
|
|
);
|
|
shell(
|
|
"ls -1 $ENV{WDIR}/my_cferom_rootfs${i}kb_puresqubi.img $ENV{WDIR}/custom_$ENV{PROFILE}_cferom_puresqubi_${i}.w \\
|
|
$ENV{WDIR}/custom_$ENV{PROFILE}_puresqubi_${i}.w"
|
|
);
|
|
}
|
|
|
|
shell("rm -f $ENV{WDIR}$ENV{CFE_ROM_BN}$ENV{FLD_ENC} $ENV{WDIR}$ENV{CFE_ROM_BN}$ENV{MFG_ENC}");
|
|
shell("mv $ENV{WDIR}/bootfs $ENV{WDIR}/bootfs.$$");
|
|
shell("mv $ENV{WDIR}/head $ENV{WDIR}/head.$$");
|
|
print "$0 completed \n";
|