5 Shared State Signing
The OpenEmbedded Build System build system has a built-in mechanism allowing to save execution time by re-using pre-built artifacts: the shared state cache (sstate cache). These artifacts are stored in a directory (SSTATE_DIR) and are not signed by default.
This document goes through the steps to enable shared state signing.
This feature is fully dependent on GPG, meaning
examples shown in this document will use the gpg command-line tool.
5.1 Host Requirements
As GPG is not part of the default host requirements, you will need to install it on your host.
For example, Debian-based distributions provide it with the gpg package.
Install it as follows:
$ sudo apt-get install gpg
Verify that your installation is successful by showing the version of GPG:
$ gpg --version
5.2 Generating A Public And Private Key Pair With GPG
Note
This step is optional if you already have a pair of public and private keys.
You need a pair of public and private keys for two independent tasks:
Signing the shared state artifacts that the OpenEmbedded Build System generates with your private key.
Verifying the shared state artifacts with your public key when re-using them.
Note
For more information on public key cryptography, see https://en.wikipedia.org/wiki/Public-key_cryptography.
With the gpg command-line tool, generate a new pair of public and private
keys:
$ gpg --full-generate-key
It will guide you through the steps of creating the key pair.
Once done, you should be able to list your new key with the following command:
$ gpg --list-keys
pub ed25519 2026-04-17 [SC]
4049A47E3AAA99D0250966DC5B97632FA7F4E942
uid [ultimate] Antonin Godard (SState Signing) <antonin.godard\@bootlin.com>
sub cv25519 2026-04-17 [E]
In the above example, take note of the
4049A47E3AAA99D0250966DC5B97632FA7F4E942 key identifier. This will be used
to configure the build.
5.3 Configuring The Build System To Sign Shared State Artifacts
5.3.1 Shared State Location
The build system needs to be configured to sign new shared state artifacts when they are generated. The generation of new artifacts is done once a task has finished being executed.
For the following sections let’s assume that the build system has the shared state directory location (SSTATE_DIR) defined as follows:
SSTATE_DIR = "${TOPDIR}/sstate-cache"
Assuming this directory and the temporary directory (TMPDIR) are empty,
let’s run the create_recipe_spdx task of the gettext-minimal-native
recipe:
$ bitbake gettext-minimal-native -c create_recipe_spdx
Let’s take this command as an example throughout this document.
After execution, the shared state directory should be populated with new files:
$ find $BUILDDIR/sstate-cache/ -name "*gettext-minimal-native*create_recipe_spdx*"
sstate-cache/universal/a3/6e/sstate:gettext-minimal-native:x86_64-linux:1.0:r0:x86_64:14:a36ef66df6b8c0cb5a849bc70a99dcfd61e4bacd11cefe6bbaf4978b2b3b617a_create_recipe_spdx.tar.zst
sstate-cache/universal/a3/6e/sstate:gettext-minimal-native:x86_64-linux:1.0:r0:x86_64:14:a36ef66df6b8c0cb5a849bc70a99dcfd61e4bacd11cefe6bbaf4978b2b3b617a_create_recipe_spdx.tar.zst.siginfo
These are the default shared state artifacts generated by the OpenEmbedded Build System. They are not signed with GPG by default, so let’s see how to add signing of these artifacts.
Note
Despite its name, the siginfo file is unrelated to GPG signing.
5.3.2 Enabling Shared State Signing
Create a new configuration file on your host in a safe location and add the two following statements:
SSTATE_VERIFY_SIG = "1"
SSTATE_SIG_KEY = "4049A47E3AAA99D0250966DC5B97632FA7F4E942"
SSTATE_SIG_PASSPHRASE = "<your GPG key passphrase>"
It is advised to put these statements in a separate file as those contain
secrets and should not be shared. For this example, let’s assume this file is
conf/sstate-sig-key.conf.
You can make sure this file is only owned by you and not readable by another user with:
$ chown $USER:$USER conf/sstate-sig-key.conf
$ chmod o-rwx conf/sstate-sig-key.conf
The statements in this file define:
SSTATE_VERIFY_SIG: setting this variable to “1” enables the shared state signing feature.
SSTATE_SIG_KEY: the GPG key identifier for signing shared state artifacts with the private key.
In the example, this corresponds to the identifier printed with the
gpg --list-keyscommand above.SSTATE_SIG_PASSPHRASE: the passphrase used to protect your private key, chosen when creating the key pair.
Let’s test the configuration:
Continuing with the
gettext-minimal-nativeexample, let’s first remove the existing shared state artifacts, to make sure the shared state artifacts for mydo_create_recipe_spdxtask are re-generated:$ rm -r sstate-cache/
Run the
create_recipe_spdxtask forgettext-minimal-native, but this time pass the newsstate-sig-key.conffile to BitBake:$ bitbake -R conf/sstate-sig-key.conf gettext-minimal-native -c create_recipe_spdx
List the files in the shared state directory again:
$ find sstate-cache/ -name "*gettext-minimal-native*create_recipe_spdx*"
sstate-cache/universal/a3/6e/sstate:gettext-minimal-native:x86_64-linux:1.0:r0:x86_64:14:a36ef66df6b8c0cb5a849bc70a99dcfd61e4bacd11cefe6bbaf4978b2b3b617a_create_recipe_spdx.tar.zst
sstate-cache/universal/a3/6e/sstate:gettext-minimal-native:x86_64-linux:1.0:r0:x86_64:14:a36ef66df6b8c0cb5a849bc70a99dcfd61e4bacd11cefe6bbaf4978b2b3b617a_create_recipe_spdx.tar.zst.sig
sstate-cache/universal/a3/6e/sstate:gettext-minimal-native:x86_64-linux:1.0:r0:x86_64:14:a36ef66df6b8c0cb5a849bc70a99dcfd61e4bacd11cefe6bbaf4978b2b3b617a_create_recipe_spdx.tar.zst.siginfo
A new .sig file was created: this means the artifact was successfully
signed, and the signature is stored in a separate .sig file.
5.4 Verifying Signed Shared State Artifacts
Now that you have set up the build to sign shared state artifacts, let’s see how you can verify them with the public key counterpart of the private key.
Note
Signature of shared state and its verification can happen on two different hosts, meaning one host can be in charge of the signature while another only verifies the artifacts. This is preferred as the private key should not be shared between multiple hosts.
From a configuration file such as the site configuration file, include the following statements:
SSTATE_VERIFY_SIG = "1"
SSTATE_VALID_SIGS = "5B97632FA7F4E942"
These statements define:
SSTATE_VERIFY_SIG: setting this variable to “1” enables the shared state signing feature.
SSTATE_VALID_SIGS: a space-separated list of key identifiers for which shared state artifacts are accepted.
This means that shared state will be reused only if it was signed with the private key corresponding to key identifier.
You’ll notice the short-form of the key identifier here, which are the last 16 characters of the long-form key identifier shown with
gpg --list-keys(in bold text below):pub ed25519 2026-04-17 [SC] 4049A47E3AAA99D0250966DC5B97632FA7F4E942 uid [ultimate] Antonin Godard (SState Signing) <antonin.godard@bootlin.com> sub cv25519 2026-04-17 [E]
Let’s verify that signature verification works:
First, remove temporary outputs (TMPDIR) from the previous builds, to make the OpenEmbedded Build System rebuild everything using the shared state:
$ rm -rf tmp/
Then, run the task again:
$ bitbake gettext-minimal-native -c create_recipe_spdx
To make sure the shared state artifact was successfully used, look for the setscene task for
create_recipe_spdxin the latest log file from BitBake:$ grep create_recipe_spdx_setscene tmp/log/cooker/<machine>/console-latest.log NOTE: Running setscene task 1 of 1 (../layers/openembedded-core/meta/recipes-core/gettext/gettext-minimal-native_1.0.bb:do_create_recipe_spdx_setscene) NOTE: recipe gettext-minimal-native-1.0-r0: task do_create_recipe_spdx_setscene: Started NOTE: recipe gettext-minimal-native-1.0-r0: task do_create_recipe_spdx_setscene: Succeeded
The shared state was successfully verified and used!
Note
To make sure shared state verification is working, you can set a “fake” public key identifier in SSTATE_VALID_SIGS:
SSTATE_VALID_SIGS = "CAFECAFECAFECAFE"
Remove the temporary outputs again:
$ rm -r tmp/
Now, try executing the task:
$ bitbake gettext-minimal-native -c create_recipe_spdx
You should have warnings from BitBake printed on the console:
WARNING: gettext-minimal-native-1.0-r0 do_create_recipe_spdx_setscene: No accepted signatures found. Good signatures found: 5B97632FA7F4E942.
WARNING: gettext-minimal-native-1.0-r0 do_create_recipe_spdx_setscene: Cannot verify signature on sstate package ../build/sstate-cache/universal/a3/6e/sstate:gettext-minimal-native:x86_64-linux:1.0:r0:x86_64:14:a36ef66df6b8c0cb5a849bc70a99dcfd61e4bacd11cefe6bbaf4978b2b3b617a_create_recipe_spdx.tar.zst, skipping acceleration...
WARNING: gettext-minimal-native-1.0-r0 do_create_recipe_spdx_setscene: No sstate archive obtainable, will run full task instead.
WARNING: Logfile for failed setscene task is ../build/tmp/work/x86_64-linux/gettext-minimal-native/1.0/temp/log.do_create_recipe_spdx_setscene.6994
WARNING: Setscene task (../layers/openembedded-core/meta/recipes-core/gettext/gettext-minimal-native_1.0.bb:do_create_recipe_spdx_setscene) failed with exit code '1' - real task will be run instead
As you can see, this does not prevent BitBake from continuing, but the real task is executed instead of re-using the shared state.