Commit e538967b authored by Stefano Babic's avatar Stefano Babic
Browse files

Adjusted initramfs to read a configuration



The initram,fs startup script reads a configuration file
(/etc/default/initramfs) to know if:
- rootfs must be verified
- rootfs is encrypted

Change initramfs to load key from blob, and start encrypted rootfs
Signed-off-by: Stefano Babic's avatarStefano Babic <sbabic@denx.de>
parent c6cb774b
......@@ -219,8 +219,6 @@ On boot the initramfs is performing the reverse process to verify the digital si
# +------------+
The implementation is done in *verifyfs.inc*
### encrypted rootfs (read only squashfs)
As rootfs we use a read-only squashfs (ramdisk). The rootfs is crypted
......
#!/bin/sh
#
# check if rootfs is signed correct and if so encrypt it
#
# start preinit
#set -x
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MB=$((1024*1024))
MAGIC="0x5353495f53435858" # SSI_SCXX
MAGIC_LEN=8
MAGIC_SIZE="4096"
BIN_SIG=/tmp/bin.sig
BIN_DIGEST=/tmp/bin.digest
ROOT_MNT="/mnt"
ROOT_DEV=""
ROOT_OPT="-o,ro,noatime,discard,nodelalloc"
ROOT_OPT="-o ro"
# mount/umount
MOUNT="/bin/mount"
UMOUNT="/bin/umount"
# init
INIT="/sbin/init"
if [ -z ${INIT} ];then
INIT=/sbin/init
fi
#include functions
. /etc/default/initramfs
VERBOSE="yes"
mount_pseudo_fs() {
$MOUNT -t devtmpfs none /dev
$MOUNT -t tmpfs tmp /tmp
$MOUNT -t proc proc /proc
$MOUNT -t sysfs sysfs /sys
debug "Mount pseudo fs"
${MOUNT} -t devtmpfs none /dev
${MOUNT} -t tmpfs tmp /tmp
${MOUNT} -t proc proc /proc
${MOUNT} -t sysfs sysfs /sys
}
umount_pseudo_fs() {
$UMOUNT /dev
$UMOUNT /tmp
$UMOUNT /proc
$UMOUNT /sys
debug "Umount pseudo fs"
${UMOUNT} /dev
${UMOUNT} /tmp
${UMOUNT} /proc
${UMOUNT} /sys
}
parse_cmdline() {
#Parse kernel cmdline to extract base device path
CMDLINE="$(cat /proc/cmdline)"
#echo "Kernel cmdline: $CMDLINE"
for c in ${CMDLINE}; do
if [ "${c:0:5}" == "root=" ]; then
ROOT_DEV="${c:5}"
fi
done
detect_imx_crypto_engine() {
crypt_acc="caam"
# detect if CAAM or DCP is the engine
cat /proc/crypto | grep -i dcp >/dev/null
if [ $? == 0 ];then
crypt_acc="dcp"
fi
}
error_exit() {
echo "Fatal error!"
led_set_error
# wait 5 seconds and reboot
sleep 5
reboot -f
echo "ERROR: ${@}" > /dev/console
if [ "$DEBUGSHELL" != "no" ]; then
echo "enter debugshell"
/bin/sh
else
# wait 5 seconds then reboot
echo "Reboot in 5 seconds..." > /dev/console
sleep 5
reboot -f
fi
}
keyblobpath=/tmp/dmcrypt.blob
storedevice=/sys/class/i2c-dev/i2c-0/device/0-0050/eeprom
error() {
logger -t error -s "${@}"
}
# load key blob into $keyblobpath
# check, if key is valid (calculate md5sum and check
# if it is != dc6c58c971715e8043baef058b675eec
# which is the md5sum, if key contains only 0xff)
#
# Currently, if key is invalid, we create the key
# but this must be removed for production initramfs
# as CRYPT_KEY contains the raw key, which never
# should be visible.
create_key_blob() {
debug() {
if [ "$VERBOSE" != "no" ]; then
echo "${@}"
else
if [ "$ENABLELOG" != "no" ]; then
logger -s "${@}"
fi
fi
}
parse_cmdline() {
#Parse kernel cmdline to extract base device path
CMDLINE="$(cat /proc/cmdline)"
debug "Kernel cmdline: $CMDLINE"
for c in ${CMDLINE}; do
if [ "${c:0:5}" == "root=" ]; then
ROOT_DEV="${c:5}"
fi
done
debug "ROOT_DEV $ROOT_DEV"
# Load the dcpblob from storage device to $keyblobpath
# dmcrypt dcp blob @ 1k size = 128 bytes
dd of=$keyblobpath if=$storedevice bs=128 skip=8 count=1 2> /dev/null
grep enablelog /proc/cmdline > /dev/null
if [ $? -eq 0 ]; then
ENABLELOG="yes"
fi
grep debugshell /proc/cmdline > /dev/null
if [ $? -eq 0 ]; then
DEBUGSHELL="yes"
fi
grep enterinitramfs /proc/cmdline > /dev/null
if [ $? -eq 0 ]; then
ENTERINITRAMFS="yes"
fi
}
mount_pseudo_fs
detect_imx_crypto_engine
# This is a custom fuction that MUST be provided
load_key_blob
echo "Initramfs Bootstrap..."
parse_cmdline
# Check root device
debug "Root mnt : ${ROOT_MNT}"
debug "Root device: ${ROOT_DEV}"
debug "Root opt : ${ROOT_OPT}"
if [ "${ROOT_DEV}" == "" ] || [ "${ROOT_DEV}" == "/dev/nfs" ]; then
error_exit
fi
find_magic_offset() {
if [ -z ${MAGIC_OFFSET} ];then
MAGIC_OFFSET=0
fi
if [ -z ${MAX_SIZE} ];then
MAX_SIZE="$(lsblk -b -n $1 | awk '{print $4}')"
fi
while [ ${MAGIC_OFFSET} -lt ${MAX_SIZE} ]; do
var="$(hexdump -e '"0x" 8/1 "%02x"' ${1} -s ${MAGIC_OFFSET} -n ${MAGIC_LEN})"
if [[ "${var}" == "${MAGIC}" ]]; then
debug "magic offset found @ ${MAGIC_OFFSET}"
break
fi
let "MAGIC_OFFSET += ${MB}"
done
if [[ "${MAGIC_OFFSET}" == "${MAX_SIZE}" ]]; then
echo "no magic offset found!"
error_exit
fi
}
calc_digest() {
(
dd if=${1} bs=1M count=$(expr ${MAGIC_OFFSET} / ${MB}) | openssl dgst -sha256 -binary -out ${BIN_DIGEST}
) > /dev/null 2>&1
}
extract_signature() {
SIGNATURE=/tmp/$(basename ${1}.sig)
# Signature is one 4k block further than magic offset
SIGNATURE_OFFSET="$(expr $(expr ${MAGIC_OFFSET} / 4096) + 1)"
dd if=${1} of=${SIGNATURE} bs=4k skip=${SIGNATURE_OFFSET} count=1 > /dev/null 2>&1
}
verify_signature() {
base64 -d ${SIGNATURE} > ${BIN_SIG}
openssl pkeyutl -verify -in ${BIN_DIGEST} -pubin -inkey ${PUB_KEY} -sigfile ${BIN_SIG} -pkeyopt digest:sha256 || error_exit
rm -f ${SIGNATURE} ${BIN_SIG} ${BIN_DIGEST}
}
# $1: offset
check_key() {
key_found=0
# check if there is a key
# currently we check, if there are 0xff only
# if so we have no key in i2c eeprom
md5sum $keyblobpath > /tmp/gnlmpf
grep dc6c58c971715e8043baef058b675eec /tmp/gnlmpf
# if so we have no key
if [ "${keystoredev}" == "spi" ]; then
mtd_debug read $storedevice $1 40 /tmp/keytmp > /dev/null
else
dd if=${keyblobpath} of=/tmp/keytmp bs=1 count=40
fi
md5sum /tmp/keytmp > /tmp/keytmp2
# md5sum of 0xff for 40 bytes
grep 5c7191c0bf59f6d17bbe1bb4bf222e6b /tmp/keytmp2
if [ $? -ne 0 ];then
echo "found key, do not create key"
rm /tmp/gnlmpf
return
key_found=1
fi
rm /tmp/gnlmpf
rm /tmp/keytmp*
}
encrypt_rootfs () {
debug "encrypt rootfs " $1
# Create dmcrypt blob for rootfs
keyid=$(keyctl show -x | grep dm_crypt | cut -f 1 -d " ")
keyctl add symmetric "myplainkey" "dcp load_plain ${CRYPT_KEY}" $keyid
if [ "${ENTERINITRAMFS}" == "yes" ];then
echo "enter initramfs shell"
/bin/sh
fi
# get ID for reading out dcp blob
key_id=$(keyctl show -x | grep myplainkey | cut -f 1 -d " ")
keyctl pipe $key_id > $keyblobpath
if [ "${USEENCRYPTED}" == "no" ];then
debug "rootfs not encrypted"
mkdir -p ${ROOT_MNT}
mount -t squashfs ${ROOT_OPT} $1 ${ROOT_MNT}
return
fi
#store the blob now in storage device
dd if=$keyblobpath of=$storedevice bs=1k seek=1 2> /dev/null
}
## Load dm-crypt.ko, it will create a special keyring for our caam key
insmod /lib/modules/$(uname -r)/kernel/drivers/md/dm-crypt.ko
encrypt_rootfs () {
echo "encrypt rootfs " $1
# Load dm-crypt.ko, it will create a special keyring for our dcp key
insmod /lib/modules/$(uname -r)/kernel/drivers/md/dm-crypt.ko
# Find the id of this keyring, it has the name ".dm_crypt"
# the id changes on each reboot
# debug: keyctl show -x
# should show something like that:
# Session Keyring
#│ │ <> 0x356b9274 --alswrv 0 65534 keyring: _uid_ses.0
#│ │ <> 0x208b7974 --alswrv 0 65534 \_ keyring: _uid.0
#│ │ <> 0x1659b662 --alswrv 0 0 \_ keyring: .dm_crypt
keyid=$(keyctl show -x | grep dm_crypt | cut -f 1 -d " ")
create_key_blob
# Load the blob into dcp
keyctl add symmetric "mydiskkey" "dcp load_blob $(cat $keyblobpath)" $keyid
# Activate the DM-Crypt disk, $1 is the encrypted block device
cryptsetup open -s 128 -c aes-cbc-essiv:sha256 --type plain --key-desc mydiskkey $1 cr_disk
# mount it
mkdir -p ${ROOT_MNT}
mount ${ROOT_OPT} /dev/mapper/cr_disk ${ROOT_MNT}
## Load the blob into dcp/caam
echo "LOAD keyblob no keyid"
keyctl add symmetric "mydiskkey" "${crypt_acc} load_blob $(cat $keyblobpath | tr -d '\0')" @u
echo "DONE ----------------------" $?
keyctl show -x
keyctl show -x @us
## Activate the DM-Crypt disk, $1 is the encrypted block device
cryptsetup open -s 128 -c aes-cbc-essiv:sha256 --type plain --key-desc mydiskkey $1 cr_disk > /dev/null
## mount it
mkdir -p ${ROOT_MNT}
mount ${ROOT_OPT} /dev/mapper/cr_disk ${ROOT_MNT}
if [ $? != 0 ];then
echo "Error mounting rootfs"
error_exit
fi
}
mount_pseudo_fs
wait_rootfs() {
# wait endless for rootfs, as WDT triggers if rootfs
# does not come up
debug "wait for root fs: ${ROOT_FS} ..."
DEV=$(echo $1 | cut -d "/" -f 3)
debug "DEV ${DEV}"
echo "Initramfs Bootstrap... with encrypted rootfs ..."
parse_cmdline
BLKDEV=$(echo $DEV | cut -d "p" -f 1)
PARTDEV=$(echo $DEV | cut -d "p" -f 2)
debug "BLKDEV ${BLKDEV} partdev ${PARTDEV}"
LOOP="notset"
while [ $LOOP != "FOUND" ];do
sleep 0.5
LOOP=$(dmesg | grep $BLKDEV | grep p$PARTDEV | while IFS= read -r line ; do if echo $line | grep Kernel > /dev/null; then true; else echo "FOUND"; fi; done)
done
}
ROOT_FS=$(findfs ${ROOT_DEV})
wait_rootfs ${ROOT_FS}
#Check root device
echo "Root device: $ROOT_DEV"
if [ "$ROOT_DEV" == "" ] || [ "$ROOT_DEV" == "/dev/nfs" ]; then
error_exit
if [ "x${VERIFYROOTFS}" == "xno" ];then
echo "ROOTFS verification not required, skipping..."
else
debug "Verifying root fs: ${ROOT_FS} ..."
find_magic_offset ${ROOT_FS}
calc_digest ${ROOT_FS}
extract_signature ${ROOT_FS}
verify_signature ${ROOT_FS}
fi
#Verify rootfs signature
echo "Verifying root partition: $(findfs ${ROOT_DEV}) ..."
encrypt_rootfs $(findfs ${ROOT_DEV})
encrypt_rootfs ${ROOT_DEV}
umount_pseudo_fs
#Switch to real root
exec switch_root ${ROOT_MNT} $INIT ${CMDLINE}
echo "Switch to root"
exec switch_root ${ROOT_MNT} ${INIT} ${CMDLINE}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment