Coder Social home page Coder Social logo

jonasblixt / punchboot Goto Github PK

View Code? Open in Web Editor NEW
82.0 6.0 9.0 14.99 MB

Punchboot

License: Other

Shell 4.15% Makefile 1.06% C 74.75% Assembly 2.18% Batchfile 1.75% Python 16.03% CMake 0.08%
bootloader secure-boot armv7a armv8 imx6 imx8 embedded

punchboot's Introduction

PB Logo

Coverity Build Status pre-commit.ci status codecov Documentation Status Donate

Introduction

Punchboot is a secure and fast bootloader for embedded systems. It is designed to:

  • Boot as fast as possible
  • Integrate with the SoC's secure boot functionality
  • Authenticate the next piece of software in the boot chain
  • Support A/B system partitions for atomic updates
  • Support automatic rollbacks
  • Minimize software download time in production
  • Be useful for day-to-day development

Punchboot is designed for embedded systems and therefore it has a minimalistic apporach. There is no run-time configuration, everything is configured in the board files.

Punchboot could be useful if you care about the following:

  • Boot speed
  • Secure boot
  • Downloading software quickly in production

Design

Punchboot is written in C and some assembler. Currently armv7a and armv8 is supported.

The directory layout is as follows:

Folder Description ย 
/doc Documentation
/pki Crypto keys for testing
/ Bootloader source
/src/board Board support
/src/arch Architecture support
/src/plat Platform support
/src/drivers Drivers
/tools Tools

Supported architectures:

Architecture Supported
armv7a Yes
armv8a Yes
armv7m Yes

Supported platforms:

Platform Supported USB EMMC HW Crypto Secure Boot Fusebox
NXP imx6ul Yes Yes Yes Yes Yes Yes
NXP imx8m Yes Yes Yes Yes No Yes
NXP imx8x Yes Yes Yes Yes Yes Yes

Supported boards:

Board Supported More info
Jiffy Fully supported https://github.com/jonasblixt/jiffy
Bebop Fully supported https://github.com/jonasblixt/bebop
Technexion PICO-IMX8M Partial support https://www.technexion.com/products/system-on-modules/pico/pico-compute-modules/detail/PICO-IMX8M
NXP IMX8QXP MEK Fully supported https://www.nxp.com/products/processors-and-microcontrollers/arm-based-processors-and-mcus/i.mx-applications-processors/i.mx-8-processors/i.mx-8-multisensory-enablement-kit:i.MX8-MEK

Hardware accelerated signature verification

Platform RSA4096 EC secp256r1 EC secp384r1 EC secp521
NXP imx6ul Yes Yes No No
NXP imx8m Yes Yes No No
nxp imx8x yes yes yes yes
nxp imx RT no no no no

Hardware accelerated hash algorithms

Platform MD5 SHA256 SHA384 SHA512
NXP imx6ul Yes Yes No No
NXP imx8m Yes Yes No No
NXP imx8x Yes Yes Yes Yes
NXP imx RT No No No No

Secure Boot

Typical and simplified secure boot flow

  • ROM loads a set of public keys, calculates the checksum of the keys and compares the result to a fused checksum
  • ROM loads punchboot, calculates checksum and verifies signature using key's in step one
  • Run punchboot
  • Punchboot loads a PBI bundle, calculates the checksum and verifies the signature using built in keys
  • Run next step in boot chain

Most SoC:s have a boot rom that includes meachanisms for calculating a checksum of the bootloader and cryptographically verifying a signature using a public key fused to the device.

Normally fuses are a limited resource and therefor a common way is to calculate a sha256 checksum of the public key(s) and then store this checksum in fuses, this way many different public keys can be stored in a flash memory and every time the device boots it will compute a sha256 checksum and compare it to the fused checksum.

Punchboot is designed to be a part of a secure boot chain. This means that the bootloader is cryptographically signed, the ROM code of the SoC must support a mechanism to validate this signature, otherwise there is no root of trust.

When punchboot has been verified it, in turn, will load and verify the next software component in the boot chain. The bootloader only supports signed binaries.

Testing and integration tests

Punchboot uses QEMU for all module and integration tests. The 'test' platform and board target relies on virtio serial ports and block devices. The punchboot cli can be built with a domain socket transport instead of USB for communicating with an QEMU environment.

The test platform code includes gcov code that calls the QEMU semihosting API for storing test coverage data on the host.

Building and running tests:

$ cp configs/test_defconfig .config
$ make
$ make check

Device identity

Most modern SoC's provide some kind of unique identity, that is guaranteed to be unique for that particular type of SoC / Vendor etc but can not be guarateed to be globally unique.

Punchboot provides a UUID3 device identity based on a combination of the unique data from the SoC and an allocated, random, namspace UUID per platform.

When booting a linux system this information is relayed to linux through in-line patching of the device-tree. The device identity can be found in '/proc/device-tree/chosen/device-uuid'

Command mode

Command mode is entered when the system can't boot or if the bootloader is forced by a configurable, external event to do so.

In the command mode it is possible to update the bootloader, write data to partitions and install default settings. From v0.3 and forward an 'authentication cookie' must be used to interact with the bootloader to prevent malicious activity. The only command that can be executed without authentication is listing the device information (including the device UUID)

The authentication cookie consists of the device UUID encrypted with one of the active key pair's private key.

punchboot tool

The punchboot CLI is used for interacting with the command mode. A summary of the features available:

  • Update the bootloader it self
  • Manually start system A or B
  • Activate boot partitions
  • Load image to ram and execute it
  • Display basic device info
  • Configure fuses and GPT parition tables
  • Call board specific functions

The tool is written in Python and some parts in C to allow bindings for other languages. The tool is built on top of a library to make it possible to integrate with other tooling and environments.

The tool is distributed through PyPi. Binary wheels are available for Windows, Linux and macos (x86_64 and arm64).

Install using pypi:

$ pip install punchboot

Image format

Punchboot uses the bitpacker file format (https://github.com/jonasblixt/bpak)

Authentication token

Punchboot enforces authentication when the SLC (Security Life Cycle) is locked. To interact with Punchboot the session must be authenticated by using a password or a signed token.

The authentication token is generated by hashing the device UUID and signing it with one of the active key pairs.

Example:

$ punchboot dev show
Bootloader version: v0.6.1-40-ga47f-dirty
Device UUID:        0b177094-6b62-3572-902e-c1de339ecb01
Board name:         pico8ml

Creating the authentication token using the 'createtoken.sh' script located in the tools folder. In this example the private key is stored on a yubikey 5 HSM.

$ ./createtoken.sh 0B177094-6B62-3572-902E-C1DE339ECB01 pkcs11 -sha256 "pkcs11:id=%02;type=private"
engine "pkcs11" set.
Enter PKCS#11 token PIN for PIV Card Holder pin (PIV_II):
Enter PKCS#11 key PIN for SIGN key:

Authenticating the session:

$ punchboot auth token ./0B177094-6B62-3572-902E-C1DE339ECB01.token <name of a key>
Signature format: secp256r1
Hash: sha256
Authenticating using key index 0 and './0B177094-6B62-3572-902E-C1DE339ECB01.token'
Read 103 bytes
Authentication successful

Now the command mode is fully unlocked. The token is of course only valid for the individual unit with that perticular UUID.

Metrics

Measurements taken on IMX6UL, running at 528 MHz loading a 400kByte binary.

Using hardware accelerators for SHA and RSA signatures:

Parameter Value Unit
Power On Reset 28 ms
Bootloader init 7 ms
Blockdev read 13 ms
SHA256 Hash 4 ms
RSA 4096 Signaure 5 ms
Total 57 ms

Using libtomcrypt for SHA and RSA:

Parameter Value Unit
Power On Reset 28 ms
Bootloader init 7 ms
Blockdev read 13 ms
SHA256 Hash 431 ms
RSA 4096 Signaure 567 ms
Total 1046 ms

Measurements taken on IMX8QXP, loading a 14296kByte binary.

Using hardware accelerators for SHA and RSA signatures:

Parameter Value Unit
Power On Reset 175 ms
Bootloader init 6.358 ms
Blockdev read / hash 107 ms
RSA 4096 Signature 0.676 ms
Total 288 ms

The POR time is off due to some unidentified problem with the SCU firmware. A guess would be that this metric should be in the 20ms -range.

Contributing

  1. Fork the repository
  2. Implement new feature or bugfix on a branch
  3. Implement test case(s) to ensure that future changes do not break legacy
  4. Run checks: cp configs/test_defconfig .config && make check
  5. Create pull request

punchboot's People

Contributors

johnernberg avatar jonasblixt avatar mstaack avatar pre-commit-ci[bot] avatar thebolt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

punchboot's Issues

Question: FriendlyARM NEO

Hi,

Found this project and thought I would ask if progress has been made on NEO support? If not is there a timeline for this.

I Would be happy to help test. Afraid that development of that functionality however would likely be beyond my capability however.

Thanks for your hard work so far ๐Ÿ‘

Question: Is it possible to use PunchBoot for i.MX 6UL EVK?

Hey,

I've recently looked at your PunchBoot and impressed by the published boot time. We're currently working in i.MX 6UL EVK and wonder how much work is required for porting, sadly I can't find any supporting documents here.
Below are my questions regarding your amazing PunchBoot:

  1. How boot time is calculated?
  2. Are you using HAB in punchboot?
  3. How closely PunchBoot related to U-Boot?
  4. Is there any more documents available for porting?

Thanks in advance.

Various comments

https://github.com/jonpe960/punchboot/blob/master/src/gpt.c#L96

Should not be sizeof(struct gpt_primary_tbl). Replace with sizeof(gpt->backup) for less risk of errors.


https://github.com/jonpe960/punchboot/blob/master/src/gpt.c#L24-L42

len is 64 in the only place this function is used, which means maximum 128 iterations in the loop. That's more than the part->name size of 72. However as long as the name has a null termination it's fine, and I guess that's the case looking at the rest of the code base. It's not really an issue, but I mention it anyway. Also, https://github.com/jonpe960/punchboot/blob/master/src/gpt.c#L37 would write outside the buffer if the maximum number of iterations are reached.


I would define a macro #define membersof(array) (sizeof(array) / sizeof((array)[0])) and repalce this https://github.com/jonpe960/punchboot/blob/master/src/gpt.c#L113 with for (int i = 0; i < membersof(hdr->disk_uuid); i++) .


Shouldn't https://github.com/jonpe960/punchboot/blob/master/src/include/pb/gpt.h#L55 use GPT_PART_NAME_MAX_SIZE?


https://github.com/jonpe960/punchboot/blob/master/src/plat/imx/caam.c#L437

Maybe use memcmp() instead?


https://github.com/jonpe960/punchboot/blob/master/src/plat/imx/caam.c#L449

The fail print will never be executed as the function returns just before this log point.


https://github.com/jonpe960/punchboot/blob/master/src/plat/imx/caam.c#L405

This variable is not needed at all, just use err.


https://github.com/jonpe960/punchboot/blob/master/src/plat/imx/caam.c#L278

This code doesn't add any value.


https://github.com/jonpe960/punchboot/blob/master/src/plat/imx/caam.c#L99-L119

The return value of this function is never used. Could it fail?


https://github.com/jonpe960/punchboot/blob/master/src/plat/imx/caam.c#L89-L92
https://github.com/jonpe960/punchboot/blob/master/src/plat/imx/caam.c#L58-L61

Checking for NULL pointer after using it looks a bit weird.


https://github.com/jonpe960/punchboot/blob/master/src/plat/imx/caam.c#L55-L83

Maybe call caam_shedule_job_async() and then caam_wait_for_job() instead of duplicating the code?


https://github.com/jonpe960/punchboot/blob/master/src/recovery.c#L211

As I understand it cmd is received over USB. A range check would be appropriate.


https://github.com/jonpe960/punchboot/blob/master/src/plat/imx8m/plat.c#L43-L53

Shouldn't err be checked before accessing f->value, not after?


https://github.com/jonpe960/punchboot/blob/master/src/plat/imx/hab.c#L49

This function should return a bool, not the error code. In fact, if ocotp_read() fails with PB_ERR this function returns true, which is bad as it means the system is secure.


https://github.com/jonpe960/punchboot/blob/master/src/recovery.c#L275

Just do snprintf(version_string, sizeof(version_string), "PB %s",VERSION);.


https://github.com/jonpe960/punchboot/blob/master/src/recovery.c#L539
https://github.com/jonpe960/punchboot/blob/master/src/recovery.c#L180-L195

Is there an upper limit to cmd->size? If not an buffer overflow is possible. Also, recovery_read_data() reads into recovery_cmd_buffer, which is also passed as bfr to the same function. Then a memcpy() is done from recovery_cmd_buffer to bfr, which means the two buffers passed to memcpy() are overlapping, which is not allowed. memmove() must be used instead, or redesign of the code.


https://github.com/jonpe960/punchboot/blob/master/src/recovery.c#L512

Why is the security state read again here, and not only at the beginning of the function?


https://github.com/jonpe960/punchboot/blob/master/src/include/pb/pb.h#L93-L97

Always have parenthesis around parameters where they are used.

Also, the logic is wrong. Test with __a=11 and __sz=68, __region_start=50 and __region_end 70. The macro says these are not overlapping, when they in fact one of the buffers in contained within the other.

I suggest this instead:

#define PB_CHECK_OVERLAP(__a,__sz,__region_start, __region_end) \
    (((__a) <= ((uintptr_t) (__region_end))) &&                 \
     ((__a) + (__sz) >= ((uintptr_t) (__region_start))))

https://github.com/jonpe960/punchboot/blob/master/src/boot/atf_linux.c#L61

This is dead code.

build fails with a fatal error: config.h: No such file or directory

tried to build the imx8mevk target and ran into the following compilation error.

Output:

npashi@regionaltantrums: /mnt/shared/devspace/rust/projects/exp/punchboot$ make SHELL='sh -x' CROSS_COMPILE=aarch64-linux-gnu- BOARD=board/imx8mevk MKIMAGE=mkimage_imx8
+ which python3
+ BOARD=board/imx8mevk /bin/python3 scripts/genconfig.py
scripts/genconfig.py: [Errno 21] Is a directory: 'Kconfig'
+ mkdir -p build-imx8mevk
+ which bpak
+ git describe --abbrev=4 --dirty --always --tags
+ echo GEN build-imx8mevk/keystore.c
GEN build-imx8mevk/keystore.c
+ /usr/local/bin/bpak generate keystore --name pb pki/internal_keystore.bpak --decorate
+ aarch64-linux-gnu-gcc -c -std=c99 -Os -nostdlib -nostartfiles -ffunction-sections -fdata-sections -fno-omit-frame-pointer -DPB_VERSION="v0.10.0-dirty" -DLOGLEVEL=3 -DTIMING_REPORT=0 -fno-common -fno-builtin -ffreestanding -fno-exceptions -fstack-usage -MMD -MP -I lib/fdt/include -I lib/uuid/ -I. -I include/ -I lib/ -I include -I include/pb/libc -I board/imx8mevk/include -Wall -Wextra -Wunused-result -Wunused -Wdisabled-optimization -Wvla -Wshadow -Wno-unused-parameter -Wextra -Wmissing-format-attribute -Wmissing-prototypes -Wpointer-arith -Wredundant-decls -Waggregate-return -I include/pb/xlat_tables -I include/pb/xlat_tables/aarch64 -march=armv8-a -DAARCH64 -mstrict-align -mgeneral-regs-only -I arch/armv8a/include -I include/pb/libc/aarch64 -I plat/imx8m/include build-imx8mevk/keystore.c -o build-imx8mevk/keystore.o
+ git describe --abbrev=4 --dirty --always --tags
+ mkdir -p build-imx8mevk
+ echo CC main.c
CC main.c
+ aarch64-linux-gnu-gcc -c -std=c99 -Os -nostdlib -nostartfiles -ffunction-sections -fdata-sections -fno-omit-frame-pointer -DPB_VERSION="v0.10.0-dirty" -DLOGLEVEL=3 -DTIMING_REPORT=0 -fno-common -fno-builtin -ffreestanding -fno-exceptions -fstack-usage -MMD -MP -I lib/fdt/include -I lib/uuid/ -I. -I include/ -I lib/ -I include -I include/pb/libc -I board/imx8mevk/include -Wall -Wextra -Wunused-result -Wunused -Wdisabled-optimization -Wvla -Wshadow -Wno-unused-parameter -Wextra -Wmissing-format-attribute -Wmissing-prototypes -Wpointer-arith -Wredundant-decls -Waggregate-return -I include/pb/xlat_tables -I include/pb/xlat_tables/aarch64 -march=armv8-a -DAARCH64 -mstrict-align -mgeneral-regs-only -I arch/armv8a/include -I include/pb/libc/aarch64 -I plat/imx8m/include main.c -o build-imx8mevk/main.o
In file included from main.c:12:
include/pb/pb.h:18:10: fatal error: config.h: No such file or directory
   18 | #include <config.h>
      |          ^~~~~~~~~~
compilation terminated.
make: *** [Makefile:152: build-imx8mevk/main.o] Error 1

On another note: I've been working on a similar project - rustBoot and am looking to add support for the NXP i.MX8 chip-set. I'm hoping you could point me in the right direction w.r.t a couple of questions.

  1. I couldn't find documentation on NXP's container format. Would you happen to know where I could find details on the container-layout (i.e. which bytes mean what). Also is there a tool (of some sort) that can be used to inspect these containers.
  2. I presume ROM-code uses container (fields) to determine where to load and execute the next-stage bootloader.

Possible password auth bypass on iMX8

Good day!

While performing an audit of an unrelated punchboot fork, I've noticed a potential security flaw in the mainline code. It affects the imx8qxmek board when built with CONFIG_AUTH_METHOD_PASSWORD=y.

Note: This is untested, as I have no board to run vanilla punchboot on. My apologies for this.

The user performs an auth command, which is represented by a struct pb_command_authenticate:

struct pb_command_authenticate *auth_cmd = \

The size field of that struct is used here:

rc = board_command_mode_auth((char *) buffer[0], auth_cmd->size);

If the auth command is using the password method, that user-controlled(?) size is passed as length in a call to board_command_mode_auth(char *password, size_t length):

int board_command_mode_auth(char *password, size_t length)

The proper secret is read from storage and the incoming password is hashed. The two are then compared using memcmp(secret, hash, length) here:

if (memcmp(secret, hash, length) == 0) {

According to POSIX, memcmp(X, Y, 0) always returns zero, i.e. authentication succeeds.

If the size is indeed controlled by the user, this appears to allow for a complete authentication bypass using an auth command with size=0.

If possible, please confirm this vulnerability. The fix ought to be to set the length of memcmp() to match the length of the hash digest rather than the size of the input.

Thank you for your time!

STM32MP1 Support

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.