[U-Boot] Complete verified uboot example

Rick Altherr raltherr at google.com
Mon Feb 27 20:58:14 UTC 2017


The projects I'm working on are based on Yocto so I've been using the
u-boot signing support that is built in there.  I believe the magic you are
looking for is in
http://git.yoctoproject.org/cgit/cgit.cgi/poky/tree/meta/classes/uboot-sign.bbclass.
Specifically, when you run 'mkimage -F -k <key-name> -K <control-dtb> -r
<fit>', the public keys will be inserted into the control dtb.  You can
then rebuild u-boot with 'make EXT_DTB=<control-dtb>' which will use the
dtb that includes the keys.

On Mon, Feb 27, 2017 at 7:34 AM, Ron Brash <ron.brash at gmail.com> wrote:

> Okay - it seems, after working my way through a bunch of the documentation
> and examples in /doc/uImage.FIT - I noticed a discrepancy
>
> /dts-v1/;
> /{
> description = "Configuration to load a Basic Kernel";
> #address-cells = <1>;
> images {
> linux_kernel at 1 {
> description = "Linux zImage";
> data = /incbin/("zImage");
> type = "kernel";
> arch = "arm";
> os = "linux";
> compression = "none";
> load =  <0x20000000>;
> entry = <0x20008000>;
> kernel-version = <1>;
> hash at 1 {
> algo = "sha256";
> };
> };
> fdt at 1 {
> description = "FDT blob";
> data = /incbin/("myboard.dtn");
> type = "flat_dt";
> arch = "arm";
> compression = "none";
> fdt-version = <1>;
> hash at 1{
> algo = "sha256";
> };
> };
> };
> configurations {
> default = "config at 1";
> config at 1{
> description = "Plain Linux";
> kernel = "linux_kernel at 1";
> fdt = "fdt at 1";
> signature at 1{
> algo = "sha256,rsa2048";
> key-name-hint = "dev_key";
> sign-images = "fdt", "kernel";
> };
> };
> };
> };
>
> Does NOT equal (for brevity - I just used the node)
>
> fdt at 1 {
> description = "FDT blob";
> data = /incbin/("myboard.dtn");
> type = "flat_dt";
> arch = "arm";
> compression = "none";
> fdt-version = <1>;
> hash at 1{
> algo = "sha256";
> };
> signature at 1{
> algo = "sha256,rsa2048";
> key-name-hint = "dev_key";
> };
> };
>
> Apparently, this causes the mkimage tooling in my particular instance to
> explain invalid blob messages.  The large example above indeed does work
> once this nuance was noticed.
>
> Next,  once the final CTRL FDT is created, how does one get it back into
> the actual u-boot binary.  Does/can mkimage insert it into the binary image
> at a particular offset?  What is the command to do so?
>
>
>
>
>
> On 23 February 2017 at 12:27, Rick Altherr <raltherr at google.com> wrote:
>
>>
>>
>> On Thu, Feb 23, 2017 at 7:48 AM, Ron Brash <ron.brash at gmail.com> wrote:
>>
>>> Hello all (and thanks Mr. Altherr for this insight),
>>>
>>> Excellent feedback and I agree that all of this needs to find a home
>>> either on the global docs on the website and/or the text-only
>>> documentation.  Regardless, this leads me to a few questions.
>>>
>>> NOTE: the use of a uboot control DTS, control DTB and control FTD even
>>> in Mr. Altherr's email is confusion provoking.  One term to rule them all
>>> is needed ;)
>>>
>>
>> Agreed.  Technically a flattened device tree (FDT) can be described in an
>> ASCII form (dts) or binary form (dtb).
>>
>>
>>>
>>> 1.)  What if a board doesn't have OR has ever been configured to use
>>> u-boot DTS (could we call this a UDTS or something friendly to
>>> differentiate that fact?); this was a point of misunderstanding until I
>>> started scampering around into arch/arm/dts/?
>>>
>>> * For example, my board is a derivative of an Atmel at91sam9g20.  It had
>>> a very generic implementation of a DTS that covered reference boards in the
>>> Linux kernel, but required a fair bit of modification to make it work.  As
>>> the at91sam(legacy platform) isn't in u-boot's source tree for a DTS - what
>>> would someone like me need to do - do we have a barebones tutorial (again I
>>> don't mind publishing such with proofing)?  Is it even required if we have
>>> a platform/board already working in the traditional u-boot way?
>>>
>>> I believe (but have no verified) that if your board is supported by
>> U-Boot without a control FDT today, you can just create one that contains
>> only the public keys.  I've gathered from the mailing list that using a
>> control FDT and the driver model is how all new boards should be
>> implemented.
>>
>>
>>> 2.)  Just to summarise - everything winds up in two binaries: u-boot and
>>> the FIT image.  So the partition scheme would more or less would look like:
>>>
>>> /-----------------
>>> * Bootstrap/ROM (optional)
>>> /----------------
>>> * U-boot
>>> *    Control DTB
>>> *         Has keys
>>>
>>
>> Only the public keys.  The private keys are never stored on the target
>> device.
>>
>>
>>> *         Driver loadout/init
>>>
>> The control FDT only describes the hardware (see
>> https://www.devicetree.org/ and http://git.kernel.org/cgit/lin
>> ux/kernel/git/torvalds/linux.git/tree/Documentation/devicet
>> ree/usage-model.txt).  U-Boot's driver model matches device drivers
>> against nodes in the FDT and starts them.
>>
>>
>>> /----------------
>>> * U-boot env
>>> *----------------
>>> * FIT image
>>>
>> The FIT shouldn't be in the U-Boot env section.  That's used by U-Boot to
>> store its persistent environment.  The FIT is a replacement for the kernel
>> image.  Keep a separate place allocated in the flash for kernel but store
>> the FIT there.
>>
>>
>>> *    ITS
>>>
>> I never really thought of it this way, but yes, that's true.  The ITS is
>> itself written in device tree syntax and gets compiled to binary form.  dtb
>> tends to get used only to describe device trees in binary form that
>> describe hardware.  Maybe we need to introduce ITB to clarify this is the
>> device tree in binary form describing the image.
>>
>>
>>> *    Kernel
>>> *    DTS
>>>
>>
>> Prefer the terms FDT or DTB.  Only the compiled form is stored in the FIT.
>>
>>
>>> *    ....
>>> /---------------
>>> * Rootfs etc...
>>> * ...
>>> /---------------
>>>
>>>
>>> 3.)  What people used to use to load X address into Z location in memory
>>> is now removed by the usage of a DTB in u-boot correct?  I assume that the
>>> u-boot DTB now does this and bootarg/bootcmd is partially done away with -
>>> as its arguments are augmented by said file.
>>>
>>
>> Not quite.  bootarg/bootcmd is still used.  What is different is that
>> booting linux with a FDT with legacy images required multiple arguments to
>> bootm.  In that case, bootarg would be 'bootm <zimage_addr> - <fdt_addr>'.
>> With a FIT, you only provide the address of the FIT itself to bootm so
>> bootarg is set to 'bootm <fit_addr>'.
>>
>>
>>>
>>> Anybody have the spare cycles to organise a
>>> web-tutorial/presentation/recording with me on a play-by-play to make
>>> all of this make sense?  I'm aiming to be in Prague for the 2017 conference
>>> in October, might be a good place to showcase this fine-tuning.
>>>
>>>
>> I'm not clear on what you are asking.  I probably have time to review
>> docs and presentations and maybe a few phone or video conference meetings.
>>
>>
>>> Ron
>>>
>>> On 22 February 2017 at 13:51, Rick Altherr <raltherr at google.com> wrote:
>>>
>>>>
>>>> On Tue, Feb 21, 2017 at 10:08 AM, Ron Brash <ron.brash at gmail.com>
>>>> wrote:
>>>>
>>>>> Hello all,
>>>>>
>>>>> I am adding verified kernel support on a board we are using and I am
>>>>> struggling to fully understand all of the concepts and steps required
>>>>> to
>>>>> pull everything together (on ARM, using ZImages and booting with a
>>>>> working
>>>>> DTB on 4.4.3x).  I also looked at the test script inside of examples,
>>>>> but
>>>>> it left me with more questions than understanding.
>>>>>
>>>>> Please correct me where appropriate in my understanding, but if I am
>>>>> confused, likely others are too and I hope this helps everyone involved
>>>>> overall.
>>>>>
>>>>
>>>> You've asked some really good questions.  Hopefully this discussion
>>>> will end up with patches to clarify the docs.
>>>>
>>>>
>>>>>
>>>>> Steps:
>>>>> ---------------------------------------------------------------
>>>>>
>>>>> First, u-boot needs to have the appropriate features enabled and to be
>>>>> built using them.  At a minimum, I suspect:
>>>>>
>>>>> CONFIG_RSA=y
>>>>> CONFIG_FIT=y
>>>>> CONFIG_FIT_SIGNATURE=y
>>>>> CONFIG_OF_CONTROL=y
>>>>>
>>>>>
>>>> Yup.  That looks right.
>>>>
>>>>
>>>>> Next, we need to derive the appropriate cryptographic primitives/keys.
>>>>>
>>>>> #Generate a private signing key (RSA2048):
>>>>> openssl genrsa -F4 -out \
>>>>> "${key_dir}"/"${key_name}".key 2048
>>>>>
>>>>> # Generate a public key:
>>>>> openssl req -batch -new -x509 \
>>>>> -key "${key_dir}"/"${key_name}".key \
>>>>> -out "${key_dir}"/"${key_name}".crt
>>>>>
>>>>>
>>>> So far so good.  In general, I suggest having multiple signing keys.
>>>> You can put all the public keys in your u-boot so an image signed with any
>>>> of those keys will be accepted.  If you happen to have a signing key
>>>> compromised, you can switch to one of the other ones.  With that other key,
>>>> you can sign an update the removes the compromised public key from future
>>>> images.
>>>>
>>>>
>>>>> Then we derive the ITS or image source file - a file that
>>>>> hints/describes
>>>>> the elements that will be verified and/or inside of the FIT image?
>>>>> Lets
>>>>> call this $FIT_ITS
>>>>>
>>>>> FIT is a container format.  Generally, you'll create a FIT that
>>>> contains the zImage, dtb, initramfs, etc.  With FIT support enabled in
>>>> u-boot, you only need to provide the single FIT image address to 'bootm'.
>>>>  u-boot will use the config section to find the individual elements, load
>>>> them into RAM as needed, and boot.
>>>>
>>>>
>>>>> / dts - v1 /;
>>>>> / {
>>>>> description = "Configuration to load a Xen Kernel";
>>>>> #address-cells = <1>;
>>>>> images {
>>>>> linux_kernel @ 1 {
>>>>> description = "Linux zImage";
>>>>> data = /incbin / ("pathToImage/zImage");
>>>>> type = "kernel";
>>>>> arch = "arm";
>>>>> os = "linux";
>>>>> compression = "none";
>>>>> load = <0xaf600000 >;
>>>>> entry = <0xaf600000 >;
>>>>> hash @ 1 {
>>>>> algo = "sha1";
>>>>> };
>>>>> };
>>>>> fdt @ 1 {
>>>>> description = "FDT blob";
>>>>> data = /incbin / ("PathToDTBUsedByBootingKernel/ex.dtb");
>>>>> type = "flat_dt";
>>>>> arch = "arm";
>>>>> compression = "none";
>>>>> load = <0xaec00000 >;
>>>>>
>>>>
>>>> You generally don't need a 'load' property for the FDT or an
>>>> initramfs.  Without one, U-Boot will allocate RAM dynamically, if needed,
>>>> and pass the relocated address to the kernel.
>>>>
>>>> hash @ 1 {
>>>>> algo = "sha1";
>>>>> };
>>>>> };
>>>>> };
>>>>> configurations {
>>>>> default = "config at 1";
>>>>> config @ 1 {
>>>>> description = "Plain Linux";
>>>>> kernel = "linux_kernel at 1";
>>>>> fdt = "fdt at 1";
>>>>> loadables = "linux_kernel at 1";
>>>>>
>>>>
>>>> 'loadables' is for other types of firmware.  You only need the 'kernel'
>>>> property for loading and booting the kernel.
>>>>
>>>>
>>>>> };
>>>>> };
>>>>> };
>>>>>
>>>>> Question: Does a signature section go into this as well? underneath the
>>>>> hash node for each value?
>>>>
>>>>
>>>>> signature at 1 {
>>>>>      algo = "sha1,rsa2048";
>>>>>      value = <...kernel signature 1...>
>>>>>  };
>>>>>
>>>>
>>>> You add a signature section to each image you want signed within the
>>>> FIT.  In your case, add one for both the kernel and FDT images.  Signatures
>>>> go _next_ to the hash section, not in it.  Omit the 'value' property as it
>>>> will be generated for you later.
>>>>
>>>>
>>>>>
>>>>> Then using the device-tree-compiler (dtc), I create a DTB for u-boot.
>>>>> This
>>>>> is the control FDT and this defines what keys are used etc..
>>>>>
>>>>
>>>> The control FDT is used for U-Boot's driver model _as well as_
>>>> providing public keys for verifying images.  Your board may not currently
>>>> use a control FDT in which case you create one from scratch.
>>>>
>>>>
>>>>>
>>>>> #Assemble control FDT for U-Boot with space for public key:
>>>>> $DTC -p 0x1000 u-boot.dts -O dtb -o u-boot.dtb
>>>>>
>>>>> Question: What is required inside of the u-boot.dts for u-boot?  Is it
>>>>> simply the same .dts used by the booting kernel, but with a section
>>>>> proclaiming the keys?
>>>>>
>>>>
>>>> This depends on the board you are using.  For example, an AST2500
>>>> requires a DTB for U-Boot to load the right drivers.  The DTB used by
>>>> U-Boot is slightly different from that used by Linux as the Linux DTB often
>>>> includes addition configuration information.  When using verified boot, the
>>>> U-Boot DTB includes the public keys whereas the FDT/DTB stored in the FIT
>>>> does not as Linux doesn't need them.
>>>>
>>>>
>>>>>
>>>>> Question:  Where will the compiled u-boot.dtb eventually go?  Is this
>>>>> put
>>>>> into a FIT image, or flashed onto the board alongside the u-boot
>>>>> bootloader
>>>>> itself?
>>>>>
>>>>
>>>> The U-Boot control FDT is compiled into the U-Boot binary.  The FDT in
>>>> the FIT is the FDT that is provided to Linux.
>>>>
>>>>
>>>>>
>>>>> Next, given that the above steps are completed, I need to create a FIT
>>>>> image with space for the signature.
>>>>>
>>>>> # Generate fitImage with space for signature:
>>>>> $MKIMG -D "-I dts -O dtb -p 2000" \
>>>>> -f f$FIT_ITS $FIT_IMG
>>>>>
>>>>> Question: Is the FIT_IMAGE the actual zimage or is it an output image
>>>>> that
>>>>> contains all of the values contained within the ITS?
>>>>>
>>>>
>>>> The latter.  It will have a compiled version of the ITS as well as the
>>>> actual images specified in the ITS (kernel, fdt).
>>>>
>>>>
>>>>>
>>>>> Next this FIT_IMAGE (assuming that this is the final FIT image that
>>>>> contains the FDT and zImage) needs to be signed and the public key
>>>>> added to
>>>>> it; given that that the key information is in the uboot.
>>>>>
>>>>
>>>> You sign the FIT_IMAGE and put the public keys in the control DTB.
>>>>
>>>>
>>>>>
>>>>> # Sign fitImage and add public key into u-boot.dtb:
>>>>> $MKIMG -D "-I dts -O dtb -p 2000" -F \
>>>>> -k "${key dir}" -K u-boot.dtb -r $FIT_IMG
>>>>>
>>>>
>>>> This is putting the public keys used by the FIT image into the control
>>>> DTB
>>>>
>>>>
>>>>>
>>>>> Then, we sign the subsequent fitImage again - correct?
>>>>>
>>>>> # Signing subsequent fitImage:
>>>>> $MKIMG -D "-I dts -O dtb -p 2000" \
>>>>> -k "${key dir}" -f $FIT_ITS -r $FIT_IMG
>>>>>
>>>>
>>>> This is generating signatures for the images in the FIT and storing
>>>> those signatures in the FIT.
>>>>
>>>>
>>>>>
>>>>> Now that all of the above is done - we need to:
>>>>> 1. Write our uboot to the flash
>>>>> 2. Write our FIT_IMAGE to flash
>>>>>
>>>>> Question: Do we write anything else to persistent storage? The ITS?
>>>>> etc..
>>>>>
>>>>
>>>> No.  Everything is contained in the U-Boot binary (control FDT
>>>> including public keys) and the FIT (images, signatures)
>>>>
>>>>>
>>>>> Question: Do we just boot using anything else or just bootm
>>>>> 0xLocationOfTheFitImageInRAM
>>>>>
>>>>
>>>> The latter.  bootm will check the config section in the FIT and use the
>>>> kernel, fdt, etc specified there.
>>>>
>>>>
>>>>>
>>>>> Greatly appreciate any assistance to all of these questions and I'm
>>>>> sure
>>>>> this threat will be of interest to anyone else too.
>>>>>
>>>>> Thanks!
>>>>
>>>> _______________________________________________
>>>>> U-Boot mailing list
>>>>> U-Boot at lists.denx.de
>>>>> http://lists.denx.de/mailman/listinfo/u-boot
>>>>>
>>>>
>>>>
>>>
>>
>
>
> --
>
>
> Ron Brash
> CTO  & Co-founder of Atlants Embedded Inc.
> www.atlantsembedded.com
> ------------------------------------------------------------------
>
> Cell +1 438 880 6441 <(438)%20880-6441>
> Email  ron.brash at gmail.com
> Blog www.pacificsimplicity.ca
> LinkedIn ca.linkedin.com/in/ronbrash/
>
>
>
> This communication is intended for the use of the recipient to which it is
> addressed, and may contain confidential, personal, and or privileged
> information. Please contact the sender immediately if you are not the
> intended recipient of this communication, and do not copy, distribute, or
> take action relying on it. Any communication received in error, or
> subsequent reply, should be deleted or destroyed.
>


More information about the U-Boot mailing list