Skip to content

scripts: add secure plo scripts with signature verification#257

Open
winderdoot wants to merge 2 commits into
masterfrom
kradzewicz/secure_plo
Open

scripts: add secure plo scripts with signature verification#257
winderdoot wants to merge 2 commits into
masterfrom
kradzewicz/secure_plo

Conversation

@winderdoot

@winderdoot winderdoot commented Feb 19, 2026

Copy link
Copy Markdown
Contributor

Introduce changes to user scripts to allow making plo root of trust

Description

  • Add a new class of asymmetrically signed plo user scripts.
  • Change strip.py elf script to allow adding metadata sections
  • Add sign_file.py script to sign elf files

Motivation and Context

On targets where plo/plo scripts are used, signing them lets plo continue the root of trust.
Required for stmn32 secureboot (YT: RTOS-1084).

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Chore (refactoring, style fixes, git/CI config, submodule management, no code logic changes)

How Has This Been Tested?

  • Already covered by automatic testing.
  • New test added: (add PR link here).
  • Tested by hand on: (armv8m55-stm32n6-nucram).

Checklist:

  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • All new and existing linter checks and tests passed.
  • My changes generate no new compilation warnings for any of the targets.

Special treatment

PR for the plo implementation of secure commands isn't ready yet, an issue with a driver came up.

  • This PR needs additional PRs to work (list the PRs, preferably in merge-order).
  • I will merge this PR by myself when appropriate.

Comment thread scripts/image_builder.py Outdated
@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello @winderdoot, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a comprehensive framework for generating and verifying secure Phoenix-RTOS Loader (PLO) scripts. The primary goal is to establish a robust root of trust by allowing PLO scripts and their associated binaries (kernel, applications) to be cryptographically signed. This ensures the integrity and authenticity of the boot process, which is a critical requirement for secure boot implementations on embedded targets.

Highlights

  • Introduction of Secure PLO Scripts: Implemented new classes and logic to support asymmetrically signed Phoenix-RTOS Loader (PLO) user scripts, enabling a root of trust mechanism for secure boot on targets like STM32.
  • ELF File Signing Utility: Added a dedicated Python script (sign_file.py) to sign ELF files using ECC (Elliptic Curve Cryptography) and embed the digital signature into a new .signature section within the ELF binary.
  • ELF Structure Modification Capabilities: Enhanced the strip.py utility with new functionalities in ElfParser to dynamically add and modify sections within ELF files, which is crucial for embedding signatures without altering existing ELF structure significantly.
  • Cryptographic Primitives Integration: Integrated Cryptodome library for ECC key handling, digital signature generation (DSS), and various SHA2 hash algorithms (SHA256, SHA384, SHA512) into the image building process.
  • Secure Command Extensions: Extended PLO command factory (PloCmdFactory) with new secure command types (PloCmdKernelSecure, PloCmdAppSecure, PloCmdCallSecure) that incorporate hash algorithms and public key verification into their definitions.
Changelog
  • scripts/image_builder.py
    • Updated copyright year to 2026.
    • Added Cryptodome and base64 imports for cryptographic operations.
    • Introduced global variables PLO_SECURE_SCRIPT_KEY and HASH_ALGO_USER_SCRIPT for secure script configuration.
    • Defined new EccCurve and HashAlgorithm enums for specifying cryptographic parameters.
    • Renamed PloScriptEncoding.STRING_MAGIC_V1 to STRING_ASCII_V1 and updated its description to include signature handling.
    • Refactored PloCmdFactory to use a generic lookup mechanism for command classes, improving extensibility.
    • Added ALIASES class variables to PloCmdKernel and PloCmdApp for alternative command names.
    • Implemented PloCmdKernelSecure for secure kernel commands, including hash algorithm and public key parameters.
    • Implemented PloCmdAppSecure for secure application/blob commands, incorporating hash algorithm and content hash calculation.
    • Implemented PloCmdCallSecure for secure call commands, supporting ECC curve, hash algorithm, and public key verification.
    • Refactored PloScript.write into _write_progs and a new write method to separate content writing from signature handling.
    • Introduced SecurePloScript class, inheriting from PloScript, to manage the signing process of the entire PLO script using ECC.
    • Modified parse_plo_script to dynamically select between PloScript and SecurePloScript based on the presence of a secure script key.
    • Updated parse_plo_script to handle a new base_cmd argument for secure command parsing.
    • Changed file opening mode in write_plo_script to w+ to allow in-place modification for signature embedding.
    • Added utility functions read_pem_priv_key, read_pem_pub_key, get_ecc_curve, and encode_public_key for cryptographic key management.
    • Extended parse_args to include command-line arguments for --private-key, --passwd, and --hash_algo to enable secure script generation.
  • scripts/sign_file.py
    • Added new script to sign ELF files using ECC.
    • Utilized Cryptodome for DSS signature generation.
    • Implemented functionality to add a new .signature section to an ELF file.
    • Calculated the hash of the ELF header and loadable segments for signing.
    • Embedded the ECDSA signature components (r and s) into the .signature section of the ELF file.
  • scripts/strip.py
    • Updated copyright year to 2026.
    • Changed enum.Flag to enum.IntFlag for improved type safety.
    • Added EI_NIDENT constant for ELF identification size.
    • Expanded ShType enum with additional ELF section types.
    • Added content methods to ElfShdr and ElfPhdr for reading section/segment data.
    • Introduced ElfShdr.from_eclass static method for creating section headers based on ELF class.
    • Modified ElfParser to correctly read the ELF identification bytes.
    • Added get_ehdr_bytes method to retrieve ELF header bytes.
    • Implemented _update_header_offsets to adjust ELF header offsets after content expansion.
    • Added add_section method to dynamically insert new sections into an ELF file, handling string table and header updates.
    • Added set_section_content method to modify the content of an existing ELF section.
Activity
  • The pull request introduces a new feature to enable secure PLO scripts.
  • The changes have been manually tested on an armv8m55-stm32n6-nucram target.
  • The author, winderdoot, intends to merge this PR independently once appropriate.
  • There is a note that the PR for the PLO implementation of secure commands is not yet ready due to a driver issue, indicating this PR is a prerequisite or part of a larger feature rollout.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for asymmetrically signed PLO user scripts, enhancing the root of trust with new 'secure' kernel, app, and call commands, pycryptodome integration, and new signing scripts like sign_file.py. While the image_builder.py refactoring and dynamic command discovery in PloCmdFactory improve maintainability, a security audit has revealed critical vulnerabilities. Specifically, there's a critical Server-Side Template Injection (SSTI) leading to Remote Code Execution, high-severity Path Traversal vulnerabilities allowing arbitrary file reads, and medium-severity issues with insecure private key password handling on the command line. Additionally, a potential bug in the script signing logic, minor improvements for exception handling, and a duplicate import require attention.

Comment thread scripts/image_builder.py
Comment on lines +350 to +351
key_path = Path(self.public_key)
self.public_key = read_pem_pub_key(key_path)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

In the PloCmdKernelSecure class, the public_key field, which is read from the input YAML file, is used to construct a file path without proper sanitization. An attacker can provide a malicious path (e.g., ../../../../etc/passwd) in the YAML configuration, causing the application to attempt to read an arbitrary file from the filesystem. This can lead to information disclosure about file existence and permissions.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe these security concerns don't really make sense, but the current shape of the command line arguments should be approved by someone.

Comment thread scripts/image_builder.py
Comment on lines +602 to +603
key_path = Path(self.public_key)
self.public_key = read_pem_pub_key(key_path)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

In the PloCmdCallSecure class, the public_key field, which is read from the input YAML file, is used to construct a file path without proper sanitization. An attacker can provide a malicious path (e.g., ../../../../etc/passwd) in the YAML configuration, causing the application to attempt to read an arbitrary file from the filesystem. This is the same vulnerability pattern as found in PloCmdKernelSecure.

Comment thread scripts/image_builder.py Outdated
Comment thread scripts/image_builder.py

# opt-in to secure user plo scripts by providing private-key
partition.add_argument("--private-key", type=Path, default=None, dest="script_privkey", help="Private ECC key path for creating a signed, secure PLO script")
partition.add_argument("--passwd", type=str, default=None, dest="privkey_pass", help="Password for encrypted private key")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

The private key password is provided as a command-line argument via --passwd. Command-line arguments can be exposed in the system's process list and shell history, making them visible to other users on the same machine. This can lead to the leakage of the private key password.

Comment thread scripts/sign_file.py
parser = argparse.ArgumentParser(description="Sign an ELF file (ECC only)")
parser.add_argument("-i", "--input", type=Path, required=True, help="Path to input ELF file")
parser.add_argument("--private-key", type=Path, required=True, help="Path to private ECC key")
parser.add_argument("--passwd", type=str, required=True, help="Password for encrypted private key")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

The private key password is provided as a command-line argument via --passwd. Command-line arguments can be exposed in the system's process list and shell history, making them visible to other users on the same machine. This can lead to the leakage of the private key password.

Comment thread scripts/image_builder.py Outdated
Comment thread scripts/image_builder.py Outdated
Comment thread scripts/strip.py Outdated
@winderdoot
winderdoot force-pushed the kradzewicz/secure_plo branch from 497f63c to 4f82c84 Compare February 25, 2026 09:11
@github-actions

github-actions Bot commented Feb 25, 2026

Copy link
Copy Markdown

Unit Test Results

9 525 tests  ±0   8 933 ✅ ±0   52m 48s ⏱️ +46s
  583 suites ±0     592 💤 ±0 
    1 files   ±0       0 ❌ ±0 

Results for commit c5e0cb3. ± Comparison against base commit 36fd8cb.

♻️ This comment has been updated with latest results.

@winderdoot
winderdoot force-pushed the kradzewicz/secure_plo branch from 4f82c84 to 348805c Compare February 25, 2026 09:29
@winderdoot
winderdoot requested a review from nalajcie February 25, 2026 09:30
@nalajcie

Copy link
Copy Markdown
Member

Initial questions:

  • Is there any document describing the proposed security model?
  • Is the current implementation extensible to rootfs targets, if not - if the above model take into account existence of them

@winderdoot

Copy link
Copy Markdown
Contributor Author

Regarding documentation we have:

And when it comes to rootfs targets:
Secure user scripts are checked in plo once before executing them. Loaded apps/blobs that aren't copied into the syspage need to be checked later by the kernel anyway to avoid time of check vs time of use attack. The same would be true for any other partitions present in rootfs targets. Elf file signatures can be used for this.

@winderdoot
winderdoot force-pushed the kradzewicz/secure_plo branch from 348805c to c5e0cb3 Compare February 25, 2026 11:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants