Skip to main content
Redhat Developers  Logo
  • AI

    Get started with AI

    • Red Hat AI
      Accelerate the development and deployment of enterprise AI solutions.
    • AI learning hub
      Explore learning materials and tools, organized by task.
    • AI interactive demos
      Click through scenarios with Red Hat AI, including training LLMs and more.
    • AI/ML learning paths
      Expand your OpenShift AI knowledge using these learning resources.
    • AI quickstarts
      Focused AI use cases designed for fast deployment on Red Hat AI platforms.
    • No-cost AI training
      Foundational Red Hat AI training.

    Featured resources

    • OpenShift AI learning
    • Open source AI for developers
    • AI product application development
    • Open source-powered AI/ML for hybrid cloud
    • AI and Node.js cheat sheet

    Red Hat AI Factory with NVIDIA

    • Red Hat AI Factory with NVIDIA is a co-engineered, enterprise-grade AI solution for building, deploying, and managing AI at scale across hybrid cloud environments.
    • Explore the solution
  • Learn

    Self-guided

    • Documentation
      Find answers, get step-by-step guidance, and learn how to use Red Hat products.
    • Learning paths
      Explore curated walkthroughs for common development tasks.
    • Guided learning
      Receive custom learning paths powered by our AI assistant.
    • See all learning

    Hands-on

    • Developer Sandbox
      Spin up Red Hat's products and technologies without setup or configuration.
    • Interactive labs
      Learn by doing in these hands-on, browser-based experiences.
    • Interactive demos
      Click through product features in these guided tours.

    Browse by topic

    • AI/ML
    • Automation
    • Java
    • Kubernetes
    • Linux
    • See all topics

    Training & certifications

    • Courses and exams
    • Certifications
    • Skills assessments
    • Red Hat Academy
    • Learning subscription
    • Explore training
  • Build

    Get started

    • Red Hat build of Podman Desktop
      A downloadable, local development hub to experiment with our products and builds.
    • Developer Sandbox
      Spin up Red Hat's products and technologies without setup or configuration.

    Download products

    • Access product downloads to start building and testing right away.
    • Red Hat Enterprise Linux
    • Red Hat AI
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products

    Featured

    • Red Hat build of OpenJDK
    • Red Hat JBoss Enterprise Application Platform
    • Red Hat OpenShift Dev Spaces
    • Red Hat Developer Toolset

    References

    • E-books
    • Documentation
    • Cheat sheets
    • Architecture center
  • Community

    Get involved

    • Events
    • Live AI events
    • Red Hat Summit
    • Red Hat Accelerators
    • Community discussions

    Follow along

    • Articles & blogs
    • Developer newsletter
    • Videos
    • Github

    Get help

    • Customer service
    • Customer support
    • Regional contacts
    • Find a partner

    Join the Red Hat Developer program

    • Download Red Hat products and project builds, access support documentation, learning content, and more.
    • Explore the benefits

Verified boot in automotive with AutoSD

Verified boot in AutoSD and Red Hat In-Vehicle Operating System

July 15, 2026
Alexander Larsson
Related topics:
ContainersSecurity
Related products:
Red Hat Enterprise Linux

    The Automotive Stream Distribution (AutoSD) and its downstream Red Hat product Red Hat In-Vehicle Operating System is an open source project targeting use of Linux in cars. One very important requirement for cars is the ability to have a verified boot. This article explains what verified boot is, how it works in AutoSD, and how you can use it.

    Verified boot means that a chain of checks limit what code is running at each stage, so that it's not possible to (deliberately or by accident) tamper with the code running in the car without it being detected. This article discusses how this is achieved in AutoSD, and how to use it.

    Supported boot mechanisms

    The two supported mechanisms for booting AutoSD are Android Verified Boot (sometimes referred to as aboot), and UEFI (sometimes just EFI). UEFI is the standard that is used on regular laptops, desktops, and servers, and supports the CPU architectures aarch64 and x86. Aboot has "android" in the name, and originates from Android phones, but it's used on other embedded devices in the Arm ecosystem, and can boot things other than Android. The boot mechanism is implemented by the hardware board firmware, not supplied by AutoSD, but it describes the interface that AutoSD relies on to boot.

    The primary goal of the boot firmware is to load a Linux kernel and an initramfs into memory, and start execution of it. The firmware checks the loaded kernel, by reading a digital signature for the loaded kernel and validating it against a public key that is built into the board firmware. This allows for the first step in a chain that leads to a verified boot.

    Android verified boot

    Aboot is a simple interface. The system has two things that it can boot, called "slots", which are differentiated by the names A and B. For each slot there is a separate partition, called boot_a and boot_b, respectively. These partitions store a standard linux kernel, an initrd, a device tree blob (DTB) and a kernel command line. At boot, the firmware looks at the internal state to see which is the active slot, loads that, and starts the kernel.

    If verification is enabled, there are two additional separate partitions, vbmeta_a and vbmeta_b. These contain the checksum of the corresponding boot partition and a signature of it. At boot, the boot partition is loaded, the signature in it is validated, and the checksum is compared to the loaded boot partition before the kernel is started.

    When the system is updated, the update is written to the inactive slot. The firmware is then instructed to boot from this new slot. This includes resetting a boot counter for the new slot, and if the system fails to boot successfully after a certain number of attempts, the firmware automatically reverts to the previous slot.

    UEFI boot

    The UEFI boot mechanism is much more complex and doesn't have a built-in A/B switching mechanism. UEFI looks into a partition known as the EFI system partition, which is a FAT filesystem, for executable files in the EFI executable file format. AutoSD supports EFI by using the ukiboot EFI program. This program implements something similar to android boot, but using the EFI interfaces. It loads either the ukiboot_a or the ukiboot_b partition, which contain a Unified Kernel Image. This is an EFI binary that contains the kernel, initramfs, and kernel command line all in a single image. This combination of EFI and ukiboot means that system boot and system updates are very similar to aboot, and supports simple, robust A/B slot switching.

    When verification (known as "secure boot" in UEFI) is enabled, each EFI binary contains a signature that is validated against a public key which was enrolled in the EFI firmware (typically in NVRAM). This means that both the ukiboot EFI binary, and the content of the ukiboot partition must be signed.

    Signing boot files

    From a technical perspective, signing the individual boot files is easy. AutoSD ships the pesign tool that signs individual EFI files by appending a signature, and the avbtool tool (part of android-tools RPM) that can create the vbmeta partition data as needed.

    However, in practice the handling of signatures is very complicated due to the security requirements involved. For example, to sign a file, you need the private key that corresponds to the public key that is deployed in the cars. Such private keys are extremely sensitive and must not be leaked. Generally private keys (at least those used in production) are stored on dedicated hardware that is disconnected from the network with only a few people having access to it. This is complicated because it means that signing is typically handled by a dedicated and sometimes external part of the organization that is not accessible by network and only by a limited number of people.

    Using bootc to sign images

    In AutoSD, disk images are built using the automotive-image-builder tool. In a build tool like that, the natural approach to image signing would ideally be to do it as part of the build. However, the sensitivity of the handling of the private key makes this approach non-viable, Instead, automotive-image-builder relies on the fact that AutoSD uses the bootc container workflow to support signatures.

    In the bootc workflow, disk images are built in two phases. First, a bootc container image is built. This looks like a regular container image and can be stored locally or on standard container registries. Such container images can be used to update existing systems, but to initialize a new system the container image has to first be converted into a disk image (with partition tables, filesystems, bootloaders, and so on) which can be flashed to a target board.

    The use of bootc leads to a signing workflow as shown in figure 1.

    Diagram of a signing workflow.
    Figure 1: Diagram of a signing workflow.

    There is a natural point in the "middle" of the build where the build is stopped and the files are sent for signing (using whatever process is available to you), and then the build can be restarted when the signed files are returned. The signed files are injected, creating a new signed bootc container which can be used to perform updates or to create a new disk image.

    Sealed images

    Signing boot files is just the first step in the boot chain. A verified boot mechanism must validate each step of the chain. The entire process looks like Figure 2.

    Diagram of a validated boot workflow.
    Figure 2: Diagram of a validated boot workflow.

    The kernel and the initrd contain code to mount the main root filesystem (containing the operating system itself and any end user programs and data). This filesystem can be rather large, so it cannot be validated entirely each time the system boots. Instead, AutoSD uses a mechanism called composefs, where the kernel dynamically validates data when accessed, based on a hierarchical checksum. The top-level image checksum is signed by a one-time private key generated during the image build. This signed checksum is validated at boot using the public key, which is stored in the initrd. Images using this approach are called "sealed" (illustrated in Figure 3).

    Diagram of a sealed image.
    Figure 3: Diagram of a sealed image.

    The sealing of images is done automatically when images are initially built. However, if a bootc container is changed after being built, for example, using a Containerfile to extend it, then the checksum of the root filesystem changes and does not match the one expected by the initramfs. To fix this, automotive-image-builder has a reseal operation that can be used to update the expected checksum in the initramfs inside a bootc image (illustrated in Figure 4).

    Diagram of resealing a changed image.
    Figure 4: Diagram of resealing a changed image.

    Unfortunately image sealing interacts with the signing of the image in complex ways:

    • Sealing changes the initramfs, which invalidates any signatures that exists on the initramfs
    • Injecting the signed initramfs into a bootc image changes the image contents which invalidates the sealing

    To handle this cyclic dependency, there is a split up version of the reseal command where you first run prepare-reseal with a build key. Then the initramfs is signed, and then the reseal operation is finished with the one-time key (illustrated in Figure 5).

    Diagram of resealing and signing an image.

    Using the tools

    Let's demonstrate how to sign and seal an image, starting with an unsigned example. A minimal manifest, called demo.aib.yml:

    name: democontent:
      rpms:
        - vim
    auth:
      root_password: ""

    Build a bootc for the default (qemu) target, and then convert the bootc into a disk image:

    $ automotive-image-builder build demo.aib.yml localhost/demo:unsigned
    $ automotive-image-builder to-disk-image localhost/demo:unsigned unsigned.img

    To test it in a virtual machine, you can run:

    $ automotive-image-runner unsigned.img

    EFI example

    This image is sealed, and EFI based. However, it is not a signed image, because there are no signatures in the EFI files. To sign the image, you must first create a one-time key and prepare to seal using it, and then extract the files for signing:

    $ openssl genpkey -algorithm ed25519 -outform PEM -out private.pem
    $ automotive-image-builder prepare-reseal --key private.pem localhost/demo:unsigned localhost/demo:prepared
    $ automotive-image-builder extract-for-signing localhost/demo:prepared to-sign
    Extracting aboot.img from /usr/lib/modules/6.12.0-168.el10iv.x86_64/aboot.img
    Extracting ukibootx64.efi from /usr/lib/bootupd/updates/EFI/centos/ukibootx64.efi
    Extracting slot_a.addon.efi from /usr/lib/bootupd/updates/EFI/centos/ukiboot_a.efi.extra.d/slot_a.addon.efi
    Extracting slot_b.addon.efi from /usr/lib/bootupd/updates/EFI/centos/ukiboot_b.efi.extra.d/slot_b.addon.efi

    At this point a directory with EFI files requires signing, like this:

    to-sign/
    ├── efi│
    ├── aboot.img
    │   ├── slot_a.addon.efi
    │   ├── slot_b.addon.efi
    │   └── ukibootx64.efi
    └── signing_info.json

    In a production environment, you hand these files over to the person responsible for signing them. But to make it possible to experiment with the signing workflow, there are some prebuilt test tools in the automotive-image-builder sources, specifically in the contrib/secure-boot directory. These include a container script for signing files and some pre-generated test keys.

    With the repo checked out, you can run this directory:

    $ podman build -t efi-signer signer
    $ podman run --privileged --rm -ti -v .:/work efi-signer \
    --certificates contrib/secure-boot/pregenerated/db.p12 \
    --password-file contrib/secure-boot/pregenerated/password \
    to-sign/efi/* 

    This signs all EFI files with the pregenerated keys. After that, re-inject the signed files and complete the sealing:

    $ automotive-image-builder inject-signed --reseal-with-key private.pem \
    localhost/demo:prepared to-sign localhost/demo:signed
    Injecting aboot.img from to-sign/efi/aboot.img
    Injecting ukibootx64.efi from to-sign/efi/ukibootx64.efi
    Injecting slot_a.addon.efi from to-sign/efi/slot_a.addon.efi
    Injecting slot_b.addon.efi from to-sign/efi/slot_b.addon.efi

    Then convert the signed container image to a disk image and run it with the pregenerated public key:

    $ automotive-image-builder to-disk-image localhost/demo:signed signed.img
    $ automotive-image-runner --secureboot-vars \
    contrib/secure-boot/pregenerated/secboot_vars.fd \
    signed.img

    You can see in the console during the log that secureboot is enabled:

    EFI stub: UEFI Secure Boot is enabled.

    At this point, remove the private.pem file to ensure it's never used for anything else. Also, creating keys like this are stored unencrypted during the signing process. These keys should be encrypted with a password (for example by passing the -aes-256-cbc argument to openssl).

    Android boot example

    Almost everything above is the same for Android verified boot, if the --target option to the initial build command is for a board that uses aboot. For testing, you can use the abootqemukvm target, and some pregenerated keys in the contrib/avb directory.

    The only real difference is the output of extract-for-signing:

    to-sign/
    ├── aboot
    │   ├── aboot.img
    │   └── vbmeta.img
    └── signing_info.json

    In this case you need some extra information from the signing_info.json file:

    {
      "signed_files": [
        {
          "type": "aboot",
          "filename": "aboot.img",
          "paths": [
            "/usr/lib/modules/6.12.0-167.el10iv.aarch64/aboot.img"
          ],
          "partition_size": 134217728
        },
        {
          "type": "vbmeta",
          "filename": "vbmeta.img",
          "paths": [
            "/usr/lib/modules/6.12.0-167.el10iv.aarch64/vbmeta.img"
          ]
        }
      ]
    }

    In particular, the partition_size information must be passed to the following avbtool commands to sign the files:

    $ avbtool add_hash_footer --image "to_sign/aboot/aboot.img" \
        --partition_name "boot" --algorithm SHA256_RSA4096 \
        --key "contrib/avb/testkey_rsa4096.pem" --rollback_index 0 \
        --partition_size 134217728
    $ avbtool make_vbmeta_image --include_descriptors_from_image "to_sign/aboot/aboot.img" \
        --algorithm SHA256_RSA4096 \
        --key "contrib/avb/testkey_rsa4096.pem" --rollback_index 0 --output "to_sign/aboot/vbmeta.img"

    The remaining steps are the same as for EFI, except when running the image, make sure to pass the --avb option to automotive-image-runner to enable android verified boot.

    Conclusion

    Verified boot in AutoSD ensures that every step in the boot chain is validated, from the firmware loading a signed kernel to the composefs-sealed root filesystem. Whether using UEFI secure boot or Android verified boot, the bootc container workflow provides a practical way to integrate signing into your build pipeline without exposing private keys to the build system.

    To get started, try the examples above with the pregenerated test keys, and consult the AutoSD documentation for more details on integrating this into your production workflow.

    Related Posts

    • Building and running Bazel applications on AutoSD: Toolchains, containers, and recommended practices

    • Reduce bootc system update size

    • Alternatives to creating bootc images from scratch

    • Installing Red Hat Enterprise Linux 10 from a bootc image with bootc

    • Control image mode updates with download-only via bootc

    • bootc: Getting started with bootable containers

    Recent Posts

    • Verified boot in automotive with AutoSD

    • Red Hat OpenShift 4.22: What dynamic plugin developers need to know

    • What's new for developers in Red Hat OpenShift 4.22

    • Simplify your performance monitoring with the pmlogger PUSH model

    • Efficiently manage host content with Red Hat Satellite's multi-CV

    What’s up next?

    Learning Path red_hat_build_of_podman_desktop feature image

    Build and run a bootable container image with image mode for RHEL and Podman Desktop

    Learn how to locally build and run a bootable container (bootc) image in...
    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Platforms

    • Red Hat AI
    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform
    • See all products

    Build

    • Developer Sandbox
    • Developer tools
    • Interactive tutorials
    • API catalog

    Quicklinks

    • Learning resources
    • E-books
    • Cheat sheets
    • Blog
    • Events
    • Newsletter

    Communicate

    • About us
    • Contact sales
    • Find a partner
    • Report a website issue
    • Site status dashboard
    • Report a security problem

    RED HAT DEVELOPER

    Build here. Go anywhere.

    We serve the builders. The problem solvers who create careers with code.

    Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

    Sign me up

    Red Hat legal and privacy links

    • About Red Hat
    • Jobs
    • Events
    • Locations
    • Contact Red Hat
    • Red Hat Blog
    • Inclusion at Red Hat
    • Cool Stuff Store
    • Red Hat Summit
    © 2026 Red Hat

    Red Hat legal and privacy links

    • Privacy statement
    • Terms of use
    • All policies and guidelines
    • Digital accessibility

    Chat Support

    Please log in with your Red Hat account to access chat support.