diff --git a/.gitignore b/.gitignore index 58aa680a..d1433703 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,11 @@ # IDE settings /.vscode +# Local OS files +.DS_Store +# Python cache +__pycache__/ +*.py[cod] # Generated documentation _build build diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..0cf4d916 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: Copyright 2025 Arm Limited and/or its affiliates +# SPDX-License-Identifier: Apache-2.0 + +PSA_API_TOOL ?= tools + +# The location of psa-api-tool must be specified +ifeq ($(wildcard $(PSA_API_TOOL)/make),) + $(error The 'PSA_API_TOOL' variable is not set, or does not point to a suitable installation of psa-api-tool) +endif + +include $(PSA_API_TOOL)/make diff --git a/README.md b/README.md index d7d58fb9..34222e1a 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ This GitHub repository contains: * Specification source files * Reference copies of the PSA Certified API header files * Examples of usage and implementation of the PSA Certified APIs +* Build tooling for rendering the specifications * Discussions of updates to the specifications * Proposed changes to the specifications @@ -77,6 +78,32 @@ Crypto Driver Interface | [1.0 Alpha-1][crypto-driver-specs] | [doc/crypto-drive Reference header files for each minor version of each API are provided in the [headers/](headers) folder. +## Building the specifications + +This repository includes the documentation build tooling in [tools/](tools). The top-level `Makefile` uses that local tool copy by default, so a normal build does not require a separate checkout of the build tools. + +The core HTML build path requires Python, Sphinx, and `make`. PDF output also requires a LaTeX toolchain with `pdflatex`. Regenerating figures can require additional tools, depending on the figure source format, including Graphviz, `wavedrompy`, PlantUML, Java, and `rsvg-convert`. + +Build one specification from the repository root with: + +```sh +make doc/crypto/html +make doc/crypto/pdf +make doc/crypto/headers +make doc/crypto/api-diff +``` + +Replace `doc/crypto` with another specification directory, such as `doc/attestation`, `doc/storage`, `doc/fwu`, `doc/status-code`, or `doc/crypto-driver`. + +Build one output format for every specification with: + +```sh +make html +make pdf +``` + +Generated output is written under [build/](build). The build guide in [tools/docs/using-psa-api-tool.md](tools/docs/using-psa-api-tool.md) describes the available targets, dependencies, and validation flow. The editing reference in [tools/docs/psa-api-tool-notes.md](tools/docs/psa-api-tool-notes.md) describes the custom directives, roles, and source conventions used by the specifications. + ## Test Suite Test suites are available to validate compliance of API implementations against the specifications for Crypto, Attestation, and Secure Storage APIs, from: diff --git a/design/rfc-01-fwu-suit/fetch-sequence.puml b/design/rfc-01-fwu-suit/fetch-sequence.puml index 565f9cc6..2c5953ee 100644 --- a/design/rfc-01-fwu-suit/fetch-sequence.puml +++ b/design/rfc-01-fwu-suit/fetch-sequence.puml @@ -5,7 +5,7 @@ ' SUIT update using the FWU API -!include atg-spec.pumh +!include psa-spec.pumh box Network participant "Update server" as server diff --git a/design/rfc-01-fwu-suit/installer-sequence.puml b/design/rfc-01-fwu-suit/installer-sequence.puml index 00fc60c6..8b87af9f 100644 --- a/design/rfc-01-fwu-suit/installer-sequence.puml +++ b/design/rfc-01-fwu-suit/installer-sequence.puml @@ -3,7 +3,7 @@ @startuml -!include atg-spec.pumh +!include psa-spec.pumh ' Complex SUIT installation using the FWU API diff --git a/design/rfc-01-fwu-suit/no-reboot-sequence.puml b/design/rfc-01-fwu-suit/no-reboot-sequence.puml index 2ed3154b..419a9239 100644 --- a/design/rfc-01-fwu-suit/no-reboot-sequence.puml +++ b/design/rfc-01-fwu-suit/no-reboot-sequence.puml @@ -3,7 +3,7 @@ @startuml -!include atg-spec.pumh +!include psa-spec.pumh ' Complex SUIT installation using the FWU API, no boot diff --git a/design/rfc-01-fwu-suit/suit-install.puml b/design/rfc-01-fwu-suit/suit-install.puml index b658fc02..3cbb7985 100644 --- a/design/rfc-01-fwu-suit/suit-install.puml +++ b/design/rfc-01-fwu-suit/suit-install.puml @@ -3,7 +3,7 @@ @startuml -!include atg-spec.pumh +!include psa-spec.pumh ' title SUIT update : advanced installers diff --git a/design/rfc-01-fwu-suit/suit-update.puml b/design/rfc-01-fwu-suit/suit-update.puml index 02fd2f99..cdf8e642 100644 --- a/design/rfc-01-fwu-suit/suit-update.puml +++ b/design/rfc-01-fwu-suit/suit-update.puml @@ -3,7 +3,7 @@ @startuml -!include atg-spec.pumh +!include psa-spec.pumh ' title SUIT update : high-level flow diff --git a/doc/attestation/about.rst b/doc/attestation/about.rst deleted file mode 100644 index aeb2edff..00000000 --- a/doc/attestation/about.rst +++ /dev/null @@ -1,140 +0,0 @@ -.. SPDX-FileCopyrightText: Copyright 2018-2020, 2022-2026 Arm Limited and/or its affiliates -.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license - -.. Releases of this specification - -.. release:: 1.0.0 - :date: June 2019 - :confidentiality: Non-confidential - - First stable release with finalized 1.0 API. - -.. release:: 1.0.1 - :date: August 2019 - :confidentiality: Non-confidential - - Recommend type byte 0x01 for arm_psa_UEID. - - Remove erroneous guidance regarding EAT’s origination claim. - -.. release:: 1.0.2 - :date: February 2020 - :confidentiality: Non-confidential - - Clarify the claim number of Instance ID. - - Permit COSE-Mac0 for signing tokens (with appropriate warning). - - Update URLs. - -.. release:: 1.0.3 - :date: October 2022 - :confidentiality: Non-confidential - - Relicensed as open source under CC BY-SA 4.0. - - CDDL definition added to the appendices. - - Example header file added to the appendices. - - Minor corrections and clarifications. - -.. release:: 1.0.4 - :date: September 2025 - :confidentiality: Non-confidential - - GlobalPlatform governance of PSA Certified evaluation scheme. - -.. release:: 2.0.0 - :date: May 2026 - :confidentiality: Non-confidential - - Updated attestation token format to the PSA attestation token. - -.. release-info:: - :extend: - - The detailed changes in each release are described in :secref:`document-history`. - -.. References used within this specification - -.. reference:: PSM - :title: Platform Security Model - :doc_no: ARM DEN 0128 - :url: developer.arm.com/documentation/den0128 - -.. reference:: PSA-STAT - :title: PSA Certified Status code API - :doc_no: ARM IHI 0097 - :url: arm-software.github.io/psa-api/status-code - -.. reference:: PSA-FFM - :title: Arm® Platform Security Architecture Firmware Framework - :doc_no: ARM DEN 0063 - :url: developer.arm.com/documentation/den0063 - -.. reference:: C99 - :title: ISO/IEC 9899:1999 --- Programming Languages --- C - :author: ISO/IEC - :publication: December 1999 - :url: www.iso.org/standard/29237.html - -.. reference:: RFC9783 - :title: Arm's Platform Security Architecture (PSA) Attestation Token - :author: H. Tschofenig, S. Frost, M. Brossard, A. Shaw, and T. Fossati - :publication: June 2025 - :url: tools.ietf.org/html/rfc9783 - -.. reference:: RFC2104 - :title: HMAC: Keyed-Hashing for Message Authentication - :author: IETF - :publication: February 1997 - :url: tools.ietf.org/html/rfc2104 - - -.. Terms used within this specification - -.. term:: Initial Attestation Key - :abbr: IAK - - Typically, the Initial Attestation Key is a secret private key from an asymmetric key-pair accessible only to the Initial Attestation service within the :term:`Platform Root of Trust`. See :cite-title:`PSM`. - -.. term:: PSA - - Platform Security Architecture - -.. term:: Platform Root of Trust - :abbr: PRoT - - The overall trust anchor for the system. This ensures the platform is securely booted and configured, and establishes the secure environments required to protect security services. See :cite-title:`PSM`. - -.. scterm:: Implementation Defined - - Behavior that is not defined by this specification, but is defined and documented by individual implementations. - - Application developers can choose to depend on :sc:`IMPLEMENTATION DEFINED` behavior, but must be aware that their code might not be portable to another implementation. - -.. term:: Secure Processing Environment - :abbr: SPE - - This is the security domain that includes the :term:`Platform Root of Trust` domain. - -.. term:: Non-secure Processing Environment - :abbr: NSPE - - This is the security domain outside of the :term:`Secure Processing Environment`. It is the application domain, typically containing the application firmware and hardware. - - - -.. potential-for-change:: - - The contents of this specification are stable for version |docversion|. - - The following may change in updates to the version |docversion| specification: - - * Small optional feature additions. - * Clarifications. - - Significant additions, or any changes that affect the compatibility of the interfaces defined in this specification will only be included in a new major or minor version of the specification. - -.. about:: diff --git a/doc/attestation/about/about.rst b/doc/attestation/about/about.rst new file mode 100644 index 00000000..8356ef34 --- /dev/null +++ b/doc/attestation/about/about.rst @@ -0,0 +1,12 @@ +.. SPDX-FileCopyrightText: Copyright 2018-2020, 2022-2026 Arm Limited and/or its affiliates +.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +.. include:: releases + +.. include:: references + +.. include:: terms + +.. include:: intro + +.. about:: diff --git a/doc/attestation/about/intro b/doc/attestation/about/intro new file mode 100644 index 00000000..6f553cb9 --- /dev/null +++ b/doc/attestation/about/intro @@ -0,0 +1,32 @@ +.. SPDX-FileCopyrightText: Copyright 2018-2020, 2022-2026 Arm Limited and/or its affiliates +.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +.. introduction:: + + This document is one of a set of resources that can help organizations develop products that meet the security requirements of GlobalPlatform's PSA Certified evaluation scheme. The PSA Certified scheme provides a framework and methodology that helps silicon manufacturers, system software providers and OEMs to develop more secure products. You can read more about PSA Certified here at :url:`www.psacertified.org`. + + .. rubric:: About the |API| + + The interface described in this document is a PSA Certified API, that provides a verifiable report of the state of the platform. The platform attestation service is provided by the :term:`Platform Root of Trust` and is described in :cite-title:`PSM`. + + The format of the attestation report that is produced by the |API| is specified in :rfc-title:`9783`. + + .. note:: + + Version 2.0 of this specification is not compatible with any 1.0 version, as a result of the change in format of the attestation report that is generated by this API. + + This document includes: + + * A set of common use cases. See :secref:`use cases`. + * The associated Application Programming Interface (API). See :secref:`api`. + + The |API| can be used either to directly produce verifiable evidence about the platform state in the context of a challenge-response interaction, or as a way to bootstrap trust in other attestation schemes. The PSA Certified framework provides the generic security features allowing OEM and service providers to integrate various attestation schemes on top of the Platform Root of Trust. + + You can find additional resources relating to the |API| here at :url:`arm-software.github.io/psa-api/attestation`, and find other PSA Certified APIs here at :url:`arm-software.github.io/psa-api`. + +.. audience:: + + This document is intended primarily for the use of developers of: + + * Root of Trust Services and security frameworks that implement the |API|. + * Root of Trust Services and Trusted Applications that implement attestation protocols which build upon the initial attestation provided by the |API|. diff --git a/doc/attestation/about/references b/doc/attestation/about/references new file mode 100644 index 00000000..ab4e8c02 --- /dev/null +++ b/doc/attestation/about/references @@ -0,0 +1,35 @@ +.. SPDX-FileCopyrightText: Copyright 2018-2020, 2022-2025 Arm Limited and/or its affiliates +.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +.. reference:: PSA STAT + :title: PSA Certified Status code API + :kind: normative + :doc_id: Arm IHI 0097 + :url: arm-software.github.io/psa-api/status-code + +.. reference:: RFC 9783 + :title: Arm's Platform Security Architecture (PSA) Attestation Token + :kind: normative + :author: H. Tschofenig, S. Frost, M. Brossard, A. Shaw, and T. Fossati + :publication: June 2025 + :url: tools.ietf.org/html/rfc9783 + +.. reference:: PSM + :title: Platform Security Model + :kind: informative + :doc_id: JSADEN014 + :author: PSA Certified + :url: psacertified.org/development-resources/building-in-security/threat-models/ + +.. reference:: C99 + :title: Programming Languages --- C + :kind: informative + :doc_id: ISO/IEC 9899:1999 + :publication: December 1999 + :url: www.iso.org/standard/29237.html + +.. reference:: RFC 2104 + :title: HMAC: Keyed-Hashing for Message Authentication + :kind: informative + :publication: February 1997 + :url: tools.ietf.org/html/rfc2104 diff --git a/doc/attestation/about/releases b/doc/attestation/about/releases new file mode 100644 index 00000000..ccf79af9 --- /dev/null +++ b/doc/attestation/about/releases @@ -0,0 +1,71 @@ +.. SPDX-FileCopyrightText: Copyright 2018-2020, 2022-2025 Arm Limited and/or its affiliates +.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +.. Releases of this specification + +.. release:: 1.0 beta 0 + :date: February 2019 + :confidentiality: Non-confidential + + Initial publication. + +.. release:: 1.0.0 + :date: June 2019 + :confidentiality: Non-confidential + + First stable release with 1.0 API finalized. + + Uses the PSA Certified API common error status codes. + + Modified the API parameters to align with other PSA Certified APIs. + + Updated the claims and lifecycle to match the latest Platform Security Model. + + Updated CBOR example in the appendix. + +.. release:: 1.0.1 + :date: August 2019 + :confidentiality: Non-confidential + + Recommend type byte 0x01 for arm_psa_UEID. + + Remove erroneous guidance regarding EAT’s origination claim. + +.. release:: 1.0.2 + :date: February 2020 + :confidentiality: Non-confidential + + Clarify the claim number of Instance ID. + + Permit COSE-Mac0 for signing tokens (with appropriate warning). + + Update URLs. + +.. release:: 1.0.3 + :date: October 2022 + :confidentiality: Non-confidential + + Relicensed as open source under CC BY-SA 4.0. + + CDDL definition added to the appendices. + + Example header file added to the appendices. + + Minor corrections and clarifications. + +.. release:: 1.0.4 + :date: September 2025 + :confidentiality: Non-confidential + + GlobalPlatform governance of PSA Certified evaluation scheme. + +.. release:: 2.0.0 + :date: May 2026 + :confidentiality: Non-confidential + + Updated attestation token format to the PSA attestation token. + +.. release-info:: + :extend: + + The detailed changes in each release are described in :secref:`document-history`. diff --git a/doc/attestation/about/terms b/doc/attestation/about/terms new file mode 100644 index 00000000..40718007 --- /dev/null +++ b/doc/attestation/about/terms @@ -0,0 +1,32 @@ +.. SPDX-FileCopyrightText: Copyright 2018-2020, 2022-2025 Arm Limited and/or its affiliates +.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +.. term:: Initial Attestation Key + :abbr: IAK + + Typically, the Initial Attestation Key is a secret private key from an asymmetric key-pair accessible only to the Initial Attestation service within the :term:`Platform Root of Trust`. See :cite-title:`PSM`. + +.. term:: PSA + + Platform Security Architecture + +.. term:: Platform Root of Trust + :abbr: PRoT + + The overall trust anchor for the system. This ensures the platform is securely booted and configured, and establishes the secure environments required to protect security services. See :cite-title:`PSM`. + +.. scterm:: Implementation Defined + + Behavior that is not defined by this specification, but is defined and documented by individual implementations. + + Application developers can choose to depend on :sc:`IMPLEMENTATION DEFINED` behavior, but must be aware that their code might not be portable to another implementation. + +.. term:: Secure Processing Environment + :abbr: SPE + + This is the security domain that includes the :term:`Platform Root of Trust` domain. + +.. term:: Non-secure Processing Environment + :abbr: NSPE + + This is the security domain outside of the :term:`Secure Processing Environment`. It is the application domain, typically containing the application firmware and hardware. diff --git a/doc/attestation/api/api.rst b/doc/attestation/api/api.rst index 5667e986..94a2101a 100644 --- a/doc/attestation/api/api.rst +++ b/doc/attestation/api/api.rst @@ -24,7 +24,7 @@ All the elements are defined in the C language. The |API| makes use of standard API conventions --------------- -All functions return a status indication of type ``psa_status_t``, which is defined by :cite-title:`PSA-STAT`. The value ``0`` (``PSA_SUCCESS``) indicates successful operation, and a negative value indicates an error. Each API documents the specific error codes that might be returned, and the meaning of each error. +All functions return a status indication of type ``psa_status_t``, which is defined by :cite-title:`PSA STAT`. The value ``0`` (``PSA_SUCCESS``) indicates successful operation, and a negative value indicates an error. Each API documents the specific error codes that might be returned, and the meaning of each error. All parameters of pointer type must be valid, non-null pointers unless the pointer is to a buffer of length 0 or the function's documentation explicitly describes the behavior when the pointer is null. For implementations where a null pointer dereference usually aborts the application, passing NULL as a function parameter where a null pointer is not allowed should abort the caller in the habitual manner. @@ -36,7 +36,7 @@ Status codes The |API| uses the status code definitions that are shared with the other PSA Certified APIs. -The following elements are defined in :file:`psa/error.h` from :cite-title:`PSA-STAT` (previously defined in :cite:`PSA-FFM`): +The following elements are defined in :file:`psa/error.h` from :cite-title:`PSA STAT`: .. code-block:: xref diff --git a/doc/attestation/appendix/history.rst b/doc/attestation/appendix/history.rst index ad3a0502..51b28c02 100644 --- a/doc/attestation/appendix/history.rst +++ b/doc/attestation/appendix/history.rst @@ -14,6 +14,12 @@ Document history * - Date - Changes + * - TBD + - *Draft GlobalPlatform publication revision* + + * Migrated the document to the 2026 PSA Certified API template. + * Changed the document front matter structure and publication styling, without changing the API. + * - June 2019 - *1.0.0* diff --git a/doc/attestation/conf.py b/doc/attestation/conf.py index b7455619..d038e2cd 100644 --- a/doc/attestation/conf.py +++ b/doc/attestation/conf.py @@ -8,7 +8,7 @@ doc_info = { # Document template - 'template': 'psa-api-2025', + 'template': 'psa-api-2026', # Document title, MANDATORY 'title': 'PSA Certified\nAttestation API', @@ -18,28 +18,21 @@ 'copyright_date': '2018-2020, 2022-2026', 'copyright': 'Arm Limited and/or its affiliates', - # Arm document identifier, marked as open issue if not provided - 'doc_id': 'IHI 0085', + # Document identifier, marked as open issue if not provided + 'doc_id': 'GPD_SPE_085', # The short X.Y version. MANDATORY 'version': '2.0', - # Arm document quality status, marked as open issue if not provided - 'quality': 'REL', - # Arm document issue number (within that version and quality status) - # Marked as open issue if not provided + # Document maintenance revision 'issue_no': 0, - # Identifies the sequence number of a release candidate of the same issue - # default to None - 'release_candidate': None, - #'draft': True, - - # Arm document confidentiality. Must be either Non-confidential or Confidential - # Marked as open issue if not provided - 'confidentiality': 'Non-confidential', + # Document draft revision + 'draft': 1, + # Document status + 'status': 'DFT', # Id of the legal notice for this document # Marked as open issue if not provided - 'license': 'psa-certified-api-license', + #'license': 'psa-certified-api-license', # Document date, default to build date 'date': 'May 2026', @@ -68,14 +61,12 @@ 'page_break': 'chapter' } -# absolute or relative path to the psa_spec material from this file -# atg_sphinx_spec_dir = '../atg-sphinx-spec' - -# Set up and run the atg-sphinx-spec configuration +# Set up and run the psa-api-tool configuration import os -atg_sphinx_spec_dir = os.environ.get('ATG_SPHINX_SPEC') or atg_sphinx_spec_dir -exec(compile(open(os.path.join(atg_sphinx_spec_dir,'atg-sphinx-conf.py'), +psa_api_tool_path = os.path.normpath(os.path.join(os.path.dirname(__file__), '..', '..', 'tools')) +psa_api_tool_path = os.environ.get('PSA_API_TOOL') or psa_api_tool_path +exec(compile(open(os.path.join(psa_api_tool_path,'psa-api-conf.py'), encoding='utf-8').read(), - 'atg-sphinx-conf.py', 'exec')) + 'psa-api-conf.py', 'exec')) diff --git a/doc/attestation/index.rst b/doc/attestation/index.rst index a816bf36..c630d07d 100644 --- a/doc/attestation/index.rst +++ b/doc/attestation/index.rst @@ -3,17 +3,9 @@ .. title:: - .. abstract:: - - This document is part of the PSA Certified API specifications. It defines interfaces to provide an attestation service for the Root of Trust. - -.. front-matter:: - - about - .. maintoc:: - overview/intro + about/about overview/use-cases overview/report api/api diff --git a/doc/attestation/overview/intro.rst b/doc/attestation/overview/intro.rst deleted file mode 100644 index 063eb5a6..00000000 --- a/doc/attestation/overview/intro.rst +++ /dev/null @@ -1,31 +0,0 @@ -.. SPDX-FileCopyrightText: Copyright 2018-2020, 2022-2025 Arm Limited and/or its affiliates -.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license - -Introduction -============ - - -About Platform Security Architecture ------------------------------------- - -This document is one of a set of resources provided by Arm that can help organizations develop products that meet the security requirements of GlobalPlatform's PSA Certified evaluation scheme on Arm-based platforms. The PSA Certified scheme provides a framework and methodology that helps silicon manufacturers, system software providers and OEMs to develop more secure products. Arm resources that support PSA Certified range from threat models, standard architectures that simplify development and increase portability, and open-source partnerships that provide ready-to-use software. You can read more about PSA Certified here at :url:`www.psacertified.org` and find more Arm resources here at :url:`developer.arm.com/platform-security-resources` and :url:`www.trustedfirmware.org`. - -About the |API| ---------------- - -The interface described in this document is a PSA Certified API, that provides a verifiable report of the state of the platform. The platform attestation service is provided by the :term:`Platform Root of Trust` and is described in :cite-title:`PSM`. - -The format of the attestation report that is produced by the |API| is specified in :rfc-title:`9783`. - -.. note:: - - Version 2.0 of this specification is not compatible with any 1.0 version, as a result of the change in format of the attestation report that is generated by this API. - -This document includes: - -- A set of common use cases. See :secref:`use cases`. -- The associated Application Programming Interface (API). See :secref:`api`. - -The |API| can be used either to directly produce verifiable evidence about the platform state in the context of a challenge-response interaction, or as a way to bootstrap trust in other attestation schemes. The PSA Certified framework provides the generic security features allowing OEM and service providers to integrate various attestation schemes on top of the Platform Root of Trust. - -You can find additional resources relating to the |API| here at :url:`arm-software.github.io/psa-api/attestation`, and find other PSA Certified APIs here at :url:`arm-software.github.io/psa-api`. diff --git a/doc/attestation/overview/report.rst b/doc/attestation/overview/report.rst index 3cdc38eb..527ca2da 100644 --- a/doc/attestation/overview/report.rst +++ b/doc/attestation/overview/report.rst @@ -10,7 +10,7 @@ The attestation report returned by the |API| is formatted and encoded as a signe The PSA Attestation Token is an incompatible evolution of the original attestation format, that was specified in version 1.0 of the |API|. -To comply with version |docversion| of the |API|, an implementation must only produce attestation reports that conform to :rfc:`9783`. +To comply with version |APIversion| of the |API|, an implementation must only produce attestation reports that conform to :rfc:`9783`. :numref:`tab-psa-token-notes` provides specific recommendations for the construction of some of the token claims. diff --git a/doc/attestation/pyproject.toml b/doc/attestation/pyproject.toml new file mode 100644 index 00000000..52de3a0e --- /dev/null +++ b/doc/attestation/pyproject.toml @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: Copyright 2026 Arm Limited and/or its affiliates +# SPDX-License-Identifier: Apache-2.0 + +[tool.esbonio] diff --git a/doc/crypto-driver/README.md b/doc/crypto-driver/README.md index 51ea3341..aa6b7bcc 100644 --- a/doc/crypto-driver/README.md +++ b/doc/crypto-driver/README.md @@ -9,7 +9,7 @@ The Crypto Driver Interface specification source files are organized as follows: Folder | Content -- | -- -Current directory | Configuration and front-matter +Current directory | Configuration and table of contents `about` | Front matter `body` | Specification chapters `appendix` | Appendices diff --git a/doc/crypto-driver/about/about.rst b/doc/crypto-driver/about/about.rst index faab1969..40f3f50d 100644 --- a/doc/crypto-driver/about/about.rst +++ b/doc/crypto-driver/about/about.rst @@ -1,42 +1,12 @@ .. SPDX-FileCopyrightText: Copyright 2025 Arm Limited and/or its affiliates .. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license +.. include:: intro + .. include:: releases .. include:: references .. include:: terms -.. release-info:: - :extend: - - The detailed changes in each release are described in :secref:`changes`. - -.. terms:: - :hide: - -.. potential-for-change:: - - This document is in active, collaborative development. - - Issues and changes are discussed in the project on Github, alongside the PSA Certified API specifications. - See :url:`github.com/arm-software/psa-api`. - - A list of open questions can be found in :secref:`open-issues`. - -.. conventions:: - :hide: - -.. current-status:: - - This document is at Alpha quality. - It is shared to support ongoing development and discussion of the architecture and interfaces for Crypto Drivers. - - The current planned scope for v1.0 is found here at :url:`github.com/ARM-software/psa-api/discussions/306`. - - There are several projects currently implementing the |API|, see :url:`github.com/arm-software/psa-api/blob/main/related-projects.md`. - - For a practical guide, with a description of the current state of drivers in Mbed TLS, see the examples in :url:`github.com/Mbed-TLS/TF-PSA-Crypto/blob/development/docs/psa-driver-example-and-guide.md`. - - .. about:: diff --git a/doc/crypto-driver/about/intro b/doc/crypto-driver/about/intro new file mode 100644 index 00000000..5b853555 --- /dev/null +++ b/doc/crypto-driver/about/intro @@ -0,0 +1,41 @@ +.. SPDX-FileCopyrightText: Copyright 2025-2026 Arm Limited and/or its affiliates +.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +.. introduction:: + + This document is one of a set of resources that can help organizations develop products that meet the security requirements of GlobalPlatform's PSA Certified evaluation scheme. The PSA Certified scheme provides a framework and methodology that helps silicon manufacturers, system software providers and OEMs to develop more secure products. You can read more about PSA Certified here at :url:`www.psacertified.org`. + + .. rubric:: About the |API| + + This document describes an interface for cryptoprocessor drivers within an implementation of the PSA Certified Crypto API. This interface complements :cite-title:`PSA CRYPT`, which describes the interface between a Crypto API implementation and an application. + + In the remainder of this document: + + * :secref:`introduction` describes the purpose of this interface. + * :secref:`overview` describes what a Crypto Driver looks like. + * :secref:`driver-description` outlines the Driver manifest. + * :secref:`driver-entry-points` provides details of driver capabilities. + * :secref:`transparent-drivers` and :secref:`opaque-drivers` explain the requirements for specific driver types. + * :secref:`using-drivers` describes how application code influences Driver selection. + +.. api-status:: + + .. warning:: **API status : ALPHA** + + This interfaces defined by this document are at Alpha quality. This document is shared to support ongoing development and discussion of the architecture and interfaces for Crypto Drivers. + + At ALPHA quality, any aspect of the interface might be changed in a future version of the document. + + The current planned scope for v1.0 is found here at :url:`github.com/ARM-software/psa-api/discussions/306`. + + There are several projects currently implementing the |API|, see :url:`github.com/arm-software/psa-api/blob/main/related-projects.md`. + + For a practical guide, with a description of the current state of drivers in Mbed TLS, see the examples in :url:`github.com/Mbed-TLS/TF-PSA-Crypto/blob/development/docs/psa-driver-example-and-guide.md`. + +.. audience:: + + This document is intended primarily for the use of developers of: + + * Software cryptographic drivers to be integrated into a framework that uses the |API|. + * Software drivers for cryptographic hardware to be integrated into a framework that uses the |API|. + * Frameworks that use the |API| to integrate software and hardware providers of cryptographic services. This includes implementations of the PSA Certified Crypto API that provide extensibility via the |API|. diff --git a/doc/crypto-driver/about/references b/doc/crypto-driver/about/references index 6beffaa9..0a4841d4 100644 --- a/doc/crypto-driver/about/references +++ b/doc/crypto-driver/about/references @@ -1,7 +1,7 @@ .. SPDX-FileCopyrightText: Copyright 2025 Arm Limited and/or its affiliates .. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license -.. reference:: PSA-CRYPT +.. reference:: PSA CRYPT :title: PSA Certified Crypto API - :doc_no: IHI 0086 + :doc_id: Arm IHI 0086 :url: arm-software.github.io/psa-api/crypto diff --git a/doc/crypto-driver/about/releases b/doc/crypto-driver/about/releases index 4ec27336..eb402826 100644 --- a/doc/crypto-driver/about/releases +++ b/doc/crypto-driver/about/releases @@ -12,3 +12,8 @@ :confidentiality: Non-confidential Republished as part of the PSA Certified APIs. + +.. release-info:: + :extend: + + The detailed changes in each release are described in :secref:`changes`. diff --git a/doc/crypto-driver/about/terms b/doc/crypto-driver/about/terms index aa4424e9..f28a7fe5 100644 --- a/doc/crypto-driver/about/terms +++ b/doc/crypto-driver/about/terms @@ -1,2 +1,8 @@ -.. SPDX-FileCopyrightText: Copyright 2025 Arm Limited and/or its affiliates +.. SPDX-FileCopyrightText: Copyright 2025-2026 Arm Limited and/or its affiliates .. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +.. terms:: + :hide: + +.. abbreviations:: + :hide: diff --git a/doc/crypto-driver/appendix/history.rst b/doc/crypto-driver/appendix/history.rst index 014cd0ea..6c4ee894 100644 --- a/doc/crypto-driver/appendix/history.rst +++ b/doc/crypto-driver/appendix/history.rst @@ -10,3 +10,13 @@ Document change history ----------------------- This section provides the detailed changes made between published version of the document. + +Changes in the draft GlobalPlatform publication revision +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Other changes +~~~~~~~~~~~~~ + +* Migrated the document to the 2026 PSA Certified API template. + + This changes the document front matter structure and publication styling, without changing the API. diff --git a/doc/crypto-driver/appendix/open-issues.rst b/doc/crypto-driver/appendix/open-issues.rst index 115b2bdb..50e02cd7 100644 --- a/doc/crypto-driver/appendix/open-issues.rst +++ b/doc/crypto-driver/appendix/open-issues.rst @@ -44,7 +44,7 @@ Use the same vendor assignment as for PSA services? Can the driver assembly process generate distinct location values as needed? This can be convenient, but it's also risky: if you upgrade a device, you need the location values to be the same between builds. -The current plan is for Arm to maintain a registry of vendors and assign a location namespace to each vendor. +The current plan is to maintain a registry of vendors and assign a location namespace to each vendor. Parts of the namespace would be reserved for implementations and integrators. Multiple transparent drivers diff --git a/doc/crypto-driver/body/introduction.rst b/doc/crypto-driver/body/introduction.rst index 88293899..a76fa458 100644 --- a/doc/crypto-driver/body/introduction.rst +++ b/doc/crypto-driver/body/introduction.rst @@ -1,11 +1,11 @@ -.. SPDX-FileCopyrightText: Copyright 2020-2025 Arm Limited and/or its affiliates +.. SPDX-FileCopyrightText: Copyright 2020-2026 Arm Limited and/or its affiliates .. SPDX-License-Identifier: CC-BY-SA-4.0 -Introduction ------------- +Crypto Driver Interface +======================= -Purpose of the driver interface -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Purpose +------- The Crypto API defines an interface that allows applications to perform cryptographic operations in a uniform way regardless of how the operations are performed. Under the hood, different keys may be stored and used in different hardware or in different logical partitions, and different algorithms may involve different hardware or software components. @@ -18,44 +18,40 @@ Functions in the Crypto API implementation invoke functions in the core. Code from the core calls drivers as described in the present document. Types of drivers -~~~~~~~~~~~~~~~~ +---------------- The PSA Cryptoprocessor driver interface supports two types of cryptoprocessors, and accordingly two types of drivers. -* **Transparent** drivers implement cryptographic operations on keys that are provided in cleartext at the beginning of each operation. - They are typically used for hardware **accelerators**. - When a transparent driver is available for a particular combination of parameters (cryptographic algorithm, key type and size, etc.), it is used instead of the default software implementation. - Transparent drivers can also be pure software implementations that are distributed as plug-ins to a Crypto API implementation (for example, an alternative implementation with different performance characteristics, or a certified implementation). -* **Opaque** drivers implement cryptographic operations on keys that can only be used inside a protected environment such as a **secure element**, a hardware security module, a smartcard, a secure enclave, etc. - An opaque driver is invoked for the specific `key location ` that the driver is registered for: the dispatch is based on the key's lifetime. +* **Transparent** drivers implement cryptographic operations on keys that are provided in cleartext at the beginning of each operation. They are typically used for hardware **accelerators**. When a transparent driver is available for a particular combination of parameters (cryptographic algorithm, key type and size, etc.), it is used instead of the default software implementation. Transparent drivers can also be pure software implementations that are distributed as plug-ins to a Crypto API implementation (for example, an alternative implementation with different performance characteristics, or a certified implementation). +* **Opaque** drivers implement cryptographic operations on keys that can only be used inside a protected environment such as a **secure element**, a hardware security module, a smartcard, a secure enclave, etc. An opaque driver is invoked for the specific `key location ` that the driver is registered for: the dispatch is based on the key's lifetime. Requirements -~~~~~~~~~~~~ +------------ The present specification was designed to fulfill the following high-level requirements. [Req.plugins] - It is possible to combine multiple drivers from different providers into the same implementation, without any prior arrangement other than choosing certain names and values from disjoint namespaces. + It is possible to combine multiple drivers from different providers into the same implementation, without any prior arrangement other than choosing certain names and values from disjoint namespaces. [Req.compile] - It is possible to compile the code of each driver and of the core separately, and link them together. - A small amount of glue code may need to be compiled once the list of drivers is available. + It is possible to compile the code of each driver and of the core separately, and link them together. + A small amount of glue code may need to be compiled once the list of drivers is available. [Req.types] - Support drivers for the following types of hardware: accelerators that operate on keys in cleartext; cryptoprocessors that can wrap keys with a built-in keys but not store user keys; and cryptoprocessors that store key material. + Support drivers for the following types of hardware: accelerators that operate on keys in cleartext; cryptoprocessors that can wrap keys with a built-in keys but not store user keys; and cryptoprocessors that store key material. [Req.portable] - The interface between drivers and the core does not involve any platform-specific consideration. - Driver calls are simple C function calls. - Interactions with platform-specific hardware happen only inside the driver (and in fact a driver need not involve any hardware at all). + The interface between drivers and the core does not involve any platform-specific consideration. + Driver calls are simple C function calls. + Interactions with platform-specific hardware happen only inside the driver (and in fact a driver need not involve any hardware at all). [Req.location] - Applications can tell which location values correspond to which secure element drivers. + Applications can tell which location values correspond to which secure element drivers. [Req.fallback] - Accelerator drivers can specify that they do not fully support a cryptographic mechanism and that a fallback to core code may be necessary. - Conversely, if an accelerator fully supports cryptographic mechanism, the core must be able to omit code for this mechanism. + Accelerator drivers can specify that they do not fully support a cryptographic mechanism and that a fallback to core code may be necessary. + Conversely, if an accelerator fully supports cryptographic mechanism, the core must be able to omit code for this mechanism. [Req.mechanisms] - Drivers can specify which mechanisms they support. - A driver's code will not be invoked for cryptographic mechanisms that it does not support. + Drivers can specify which mechanisms they support. + A driver's code will not be invoked for cryptographic mechanisms that it does not support. diff --git a/doc/crypto-driver/body/opaque.rst b/doc/crypto-driver/body/opaque.rst index 559d3054..22ff608b 100644 --- a/doc/crypto-driver/body/opaque.rst +++ b/doc/crypto-driver/body/opaque.rst @@ -1,6 +1,8 @@ .. SPDX-FileCopyrightText: Copyright 2020-2025 Arm Limited and/or its affiliates .. SPDX-License-Identifier: CC-BY-SA-4.0 +.. _opaque-drivers: + Opaque drivers -------------- diff --git a/doc/crypto-driver/body/overview.rst b/doc/crypto-driver/body/overview.rst index 692552af..0c6c705a 100644 --- a/doc/crypto-driver/body/overview.rst +++ b/doc/crypto-driver/body/overview.rst @@ -1,6 +1,8 @@ .. SPDX-FileCopyrightText: Copyright 2020-2025 Arm Limited and/or its affiliates .. SPDX-License-Identifier: CC-BY-SA-4.0 +.. _overview: + Overview of drivers ------------------- diff --git a/doc/crypto-driver/body/transparent.rst b/doc/crypto-driver/body/transparent.rst index 67595ef7..e8b6cc53 100644 --- a/doc/crypto-driver/body/transparent.rst +++ b/doc/crypto-driver/body/transparent.rst @@ -1,6 +1,8 @@ .. SPDX-FileCopyrightText: Copyright 2020-2025 Arm Limited and/or its affiliates .. SPDX-License-Identifier: CC-BY-SA-4.0 +.. _transparent-drivers: + Transparent drivers ------------------- diff --git a/doc/crypto-driver/body/using-drivers.rst b/doc/crypto-driver/body/using-drivers.rst index 3895097e..e6c0b9ae 100644 --- a/doc/crypto-driver/body/using-drivers.rst +++ b/doc/crypto-driver/body/using-drivers.rst @@ -1,6 +1,8 @@ .. SPDX-FileCopyrightText: Copyright 2020-2025 Arm Limited and/or its affiliates .. SPDX-License-Identifier: CC-BY-SA-4.0 +.. _using-drivers: + Using drivers from an application --------------------------------- diff --git a/doc/crypto-driver/conf.py b/doc/crypto-driver/conf.py index 5edc7445..d3dfb9dc 100644 --- a/doc/crypto-driver/conf.py +++ b/doc/crypto-driver/conf.py @@ -8,42 +8,36 @@ doc_info = { # Document template - 'template': 'psa-api-2025', + 'template': 'psa-api-2026', # Document title, MANDATORY 'title': 'PSA Certified\nCrypto Driver Interface', 'author': 'Arm Limited', # Document copyright date, default to year of 'date' - 'copyright_date': '2020-2025', + 'copyright_date': '2020-2026', 'copyright': 'Arm Limited and/or its affiliates', - # Arm document identifier, marked as open issue if not provided + # Document identifier, marked as open issue if not provided 'doc_id': '111106', # The short X.Y version. MANDATORY 'version': '1.0', - # Arm document quality status, marked as open issue if not provided + # Document quality status, marked as open issue if not provided 'quality': 'ALP', - # Arm document issue number (within that version and quality status) - # Marked as open issue if not provided + # Document maintenance revision 'issue_no': 1, - # Identifies the sequence number of a release candidate of the same issue - # default to None - # 'release_candidate': 1, - # Draft status - use this to indicate the document is not ready for publication - #'draft': True, - - # Arm document confidentiality. Must be either Non-confidential or Confidential - # Marked as open issue if not provided - 'confidentiality': 'Non-confidential', + # Document draft revision + 'draft': 1, + # Document status + 'status': 'DFT', # Id of the legal notice for this document # Marked as open issue if not provided - 'license': 'psa-certified-api-license', + #'license': 'psa-certified-api-license', # Document date, default to build date - 'date': '30/09/2025', + 'date': 'September 2025', # Default header file for API definitions # default to None, and can be set in documentation source @@ -55,10 +49,7 @@ # 2 : Sub-elements of API - parameters, fields, values 'header_doxygen': 2, - # Declare a watermark for the PDF output - # 'watermark': 'DRAFT', - -# List of optional content that should be included in the build. + # List of optional content that should be included in the build. # Valid options are: # 'rationale' : This enables output of ..rationale:: directives # 'banner' : This enables output of the title page banner @@ -81,17 +72,15 @@ # 'appendix' : just before the appendices # 'chapter' : before every chapter # Default to 'appendix' - #'page_break': 'chapter' + 'page_break': 'chapter' } -# absolute or relative path to the psa_spec material from this file -# atg_sphinx_spec_dir = '../atg-sphinx-spec' - -# Set up and run the atg-sphinx-spec configuration +# Set up and run the psa-api-tool configuration import os -atg_sphinx_spec_dir = os.environ.get('ATG_SPHINX_SPEC') or atg_sphinx_spec_dir -exec(compile(open(os.path.join(atg_sphinx_spec_dir,'atg-sphinx-conf.py'), +psa_api_tool_path = os.path.normpath(os.path.join(os.path.dirname(__file__), '..', '..', 'tools')) +psa_api_tool_path = os.environ.get('PSA_API_TOOL') or psa_api_tool_path +exec(compile(open(os.path.join(psa_api_tool_path,'psa-api-conf.py'), encoding='utf-8').read(), - 'atg-sphinx-conf.py', 'exec')) + 'psa-api-conf.py', 'exec')) diff --git a/doc/crypto-driver/index.rst b/doc/crypto-driver/index.rst index 73c28308..b931ce87 100644 --- a/doc/crypto-driver/index.rst +++ b/doc/crypto-driver/index.rst @@ -3,23 +3,15 @@ .. title:: - .. abstract:: - - This document describes an interface for cryptoprocessor drivers within an implementation of the PSA Certified Crypto API. - This interface complements :cite-title:`PSA-CRYPT`, which describes the interface between a Crypto API implementation and an application. - .. banner:: **ALPHA** This specification is work in progress and should be considered to be in at Alpha quality. - See :secref:`current-status` for details. - -.. front-matter:: - - about/about + See :secref:`introduction` for details. .. maintoc:: + about/about body/introduction body/overview body/manifest diff --git a/doc/crypto-driver/pyproject.toml b/doc/crypto-driver/pyproject.toml new file mode 100644 index 00000000..52de3a0e --- /dev/null +++ b/doc/crypto-driver/pyproject.toml @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: Copyright 2026 Arm Limited and/or its affiliates +# SPDX-License-Identifier: Apache-2.0 + +[tool.esbonio] diff --git a/doc/crypto/about/about.rst b/doc/crypto/about/about.rst index 148683f5..76ff93e9 100644 --- a/doc/crypto/about/about.rst +++ b/doc/crypto/about/about.rst @@ -1,37 +1,12 @@ -.. SPDX-FileCopyrightText: Copyright 2018-2022 Arm Limited and/or its affiliates +.. SPDX-FileCopyrightText: Copyright 2018-2022, 2026 Arm Limited and/or its affiliates .. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license -.. include:: releases - -.. release-info:: - :extend: +.. include:: intro - The detailed changes in each release are described in :secref:`changes`. +.. include:: releases .. include:: references -.. references:: - - This document refers to the following documents. - - .. reference-table:: Arm documents referenced by this document - :filter: arm - - .. reference-table:: Other documents referenced by this document - :filter: non-arm - :sorted: - .. include:: terms -.. potential-for-change:: - - The contents of this specification are stable for version |docversion|. - - The following may change in updates to the version |docversion| specification: - - * Small optional feature additions. - * Clarifications. - - Significant additions, or any changes that affect the compatibility of the interfaces defined in this specification will only be included in a new major or minor version of the specification. - .. about:: diff --git a/doc/crypto/about/intro b/doc/crypto/about/intro new file mode 100644 index 00000000..2cd5ad2d --- /dev/null +++ b/doc/crypto/about/intro @@ -0,0 +1,31 @@ +.. SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited and/or its affiliates +.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +.. introduction:: + + This document is one of a set of resources that can help organizations develop products that meet the security requirements of GlobalPlatform's PSA Certified evaluation scheme. The PSA Certified scheme provides a framework and methodology that helps silicon manufacturers, system software providers and OEMs to develop more secure products. You can read more about PSA Certified here at :url:`www.psacertified.org`. + + .. rubric:: About the |API| + + The interface described in this document is a PSA Certified API, that provides a portable programming interface to cryptographic operations, and key storage functionality, on a wide range of hardware. + + The interface is user-friendly, while still providing access to the low-level primitives used in modern cryptography. It does not require that the user has access to the key material. Instead, it uses opaque key identifiers. + + You can find additional resources relating to the |API| here at :url:`arm-software.github.io/psa-api/crypto`, and find other PSA Certified APIs here at :url:`arm-software.github.io/psa-api`. + + This document includes: + + * A rationale for the design. See :secref:`design-goals`. + * A high-level overview of the functionality provided by the interface. See :secref:`functionality-overview`. + * A description of typical architectures of implementations for this specification. See :secref:`architectures`. + * General considerations for implementers of this specification, and for applications that use the interface defined in this specification. See :secref:`implementation-considerations` and :secref:`usage-considerations`. + * A detailed definition of the API. See :secref:`library-management`, :secref:`key-management`, and :secref:`crypto-operations`. + +.. audience:: + + This document is intended primarily for the use of developers of: + + * Cryptographic libraries that implement the |API|. + * Root of Trust Services that implement the |API|. + * Root of Trust Services and Trusted Applications within a Secure Processing Environment or Trusted Execution Environment which use the |API| to access cryptographic and key management services. + * Client applications which use the |API| to access cryptographic and key management services. diff --git a/doc/crypto/about/references b/doc/crypto/about/references index b23bf4e7..5ac455d6 100644 --- a/doc/crypto/about/references +++ b/doc/crypto/about/references @@ -2,552 +2,569 @@ .. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license .. reference:: PSM - :title: Platform Security Model - :doc_no: ARM DEN 0128 - :url: developer.arm.com/documentation/den0128 - -.. reference:: PSA-FFM - :title: Arm® Platform Security Architecture Firmware Framework - :doc_no: ARM DEN 0063 - :url: developer.arm.com/documentation/den0063 - -.. reference:: PSA-STAT - :title: PSA Certified Status code API - :doc_no: ARM IHI 0097 - :url: arm-software.github.io/psa-api/status-code + :title: Platform Security Model + :kind: informative + :doc_id: JSADEN014 + :author: PSA Certified + :url: psacertified.org/development-resources/building-in-security/threat-models/ + +.. reference:: PSA STAT + :title: PSA Certified Status code API + :kind: normative + :doc_id: Arm IHI 0097 + :url: arm-software.github.io/psa-api/status-code .. reference:: C99 - :title: ISO/IEC 9899:1999 --- Programming Languages --- C - :author: ISO/IEC - :publication: December 1999 - :url: www.iso.org/standard/29237.html + :title: Programming Languages --- C + :kind: informative + :doc_id: ISO/IEC 9899:1999 + :publication: December 1999 + :url: www.iso.org/standard/29237.html .. reference:: NTT-CAM - :title: Specification of Camellia — a 128-bit Block Cipher - :author: NTT Corporation and Mitsubishi Electric Corporation - :publication: September 2001 - :url: info.isl.ntt.co.jp/crypt/eng/camellia/specifications + :title: Specification of Camellia — a 128-bit Block Cipher + :doc_id: Camellia + :author: NTT Corporation and Mitsubishi Electric Corporation + :publication: September 2001 + :url: info.isl.ntt.co.jp/crypt/eng/camellia/specifications .. reference:: Curve25519 - :author: Bernstein et al. - :title: Curve25519: new Diffie-Hellman speed records - :publication: LNCS 3958, 2006 - :url: www.iacr.org/archive/pkc2006/39580209/39580209.pdf + :author: Bernstein et al. + :title: Curve25519: new Diffie-Hellman speed records + :publication: LNCS 3958, 2006 + :url: www.iacr.org/archive/pkc2006/39580209/39580209.pdf .. reference:: Curve448 - :title: Ed448-Goldilocks, a new elliptic curve - :author: Hamburg - :publication: NIST ECC Workshop, 2015 - :url: eprint.iacr.org/2015/625.pdf + :title: Ed448-Goldilocks, a new elliptic curve + :author: Hamburg + :publication: NIST ECC Workshop, 2015 + :url: eprint.iacr.org/2015/625.pdf .. reference:: Ed25519 - :author: Bernstein et al. - :title: Twisted Edwards curves - :publication: Africacrypt, 2008 - :url: eprint.iacr.org/2008/013.pdf + :author: Bernstein et al. + :title: Twisted Edwards curves + :publication: Africacrypt, 2008 + :url: eprint.iacr.org/2008/013.pdf .. reference:: Ed448 - :title: Ed448-Goldilocks, a new elliptic curve - :author: Hamburg - :publication: NIST ECC Workshop, 2015 - :url: eprint.iacr.org/2015/625.pdf + :title: Ed448-Goldilocks, a new elliptic curve + :author: Hamburg + :publication: NIST ECC Workshop, 2015 + :url: eprint.iacr.org/2015/625.pdf .. reference:: FIPS180-4 - :title: FIPS Publication 180-4: Secure Hash Standard (SHS) - :author: NIST - :publication: August 2015 - :url: doi.org/10.6028/NIST.FIPS.180-4 + :title: FIPS Publication 180-4: Secure Hash Standard (SHS) + :doc_id: FIPS 180-4 + :author: NIST + :publication: August 2015 + :url: doi.org/10.6028/NIST.FIPS.180-4 .. reference:: FIPS186-4 - :title: FIPS Publication 186-4: Digital Signature Standard (DSS) - :author: NIST - :publication: July 2013 - :url: doi.org/10.6028/NIST.FIPS.186-4 + :title: FIPS Publication 186-4: Digital Signature Standard (DSS) + :doc_id: FIPS 186-4 + :author: NIST + :publication: July 2013 + :url: doi.org/10.6028/NIST.FIPS.186-4 .. reference:: FIPS197 - :title: FIPS Publication 197: Advanced Encryption Standard (AES) - :author: NIST - :publication: November 2001 - :url: doi.org/10.6028/NIST.FIPS.197 + :title: FIPS Publication 197: Advanced Encryption Standard (AES) + :doc_id: FIPS 197 + :author: NIST + :publication: November 2001 + :url: doi.org/10.6028/NIST.FIPS.197 .. reference:: FIPS202 - :title: FIPS Publication 202: SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions - :author: NIST - :publication: August 2015 - :url: doi.org/10.6028/NIST.FIPS.202 + :title: FIPS Publication 202: SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions + :doc_id: FIPS 202 + :author: NIST + :publication: August 2015 + :url: doi.org/10.6028/NIST.FIPS.202 .. reference:: FRP - :title: Publication d'un paramétrage de courbe elliptique visant des applications de passeport électronique et de l'administration électronique française - :author: Agence nationale de la sécurité des systèmes d'information - :publication: 21 November 2011 - :url: www.ssi.gouv.fr/agence/rayonnement-scientifique/publications-scientifiques/articles-ouvrages-actes + :title: Publication d'un paramétrage de courbe elliptique visant des applications de passeport électronique et de l'administration électronique française + :doc_id: FRP256v1 + :author: Agence nationale de la sécurité des systèmes d'information + :publication: 21 November 2011 + :url: cyber.gouv.fr/nous-connaitre/publications/publications-scientifiques .. reference:: IEEE-XTS - :title: 1619-2018 --- IEEE Standard for Cryptographic Protection of Data on Block-Oriented Storage Devices - :author: IEEE - :publication: January 2019 - :url: ieeexplore.ieee.org/servlet/opac?punumber=8637986 + :title: Standard for Cryptographic Protection of Data on Block-Oriented Storage Devices + :doc_id: IEEE 1619-2018 + :publication: January 2019 + :url: ieeexplore.ieee.org/servlet/opac?punumber=8637986 .. reference:: SEC1 - :title: SEC 1: Elliptic Curve Cryptography - :author: Standards for Efficient Cryptography - :publication: May 2009 - :url: www.secg.org/sec1-v2.pdf + :title: SEC 1: Elliptic Curve Cryptography + :doc_id: SEC 1 + :author: Standards for Efficient Cryptography + :publication: May 2009 + :url: www.secg.org/sec1-v2.pdf .. reference:: SEC2 - :title: SEC 2: Recommended Elliptic Curve Domain Parameters - :author: Standards for Efficient Cryptography - :publication: January 2010 - :url: www.secg.org/sec2-v2.pdf + :title: SEC 2: Recommended Elliptic Curve Domain Parameters + :doc_id: SEC 2 v2 + :author: Standards for Efficient Cryptography + :publication: January 2010 + :url: www.secg.org/sec2-v2.pdf .. reference:: SEC2v1 - :title: SEC 2: Recommended Elliptic Curve Domain Parameters, Version 1.0 - :author: Standards for Efficient Cryptography - :publication: September 2000 - :url: www.secg.org/SEC2-Ver-1.0.pdf + :title: SEC 2: Recommended Elliptic Curve Domain Parameters, Version 1.0 + :doc_id: SEC 2 v1.0 + :author: Standards for Efficient Cryptography + :publication: September 2000 + :url: www.secg.org/SEC2-Ver-1.0.pdf .. reference:: SP800-30 - :title: NIST Special Publication 800-30 Revision 1: Guide for Conducting Risk Assessments - :author: NIST - :publication: September 2012 - :url: doi.org/10.6028/NIST.SP.800-30r1 + :title: Special Publication 800-30 Revision 1: Guide for Conducting Risk Assessments + :kind: informative + :author: NIST + :publication: September 2012 + :url: doi.org/10.6028/NIST.SP.800-30r1 .. reference:: SP800-38A - :title: NIST Special Publication 800-38A: Recommendation for Block Cipher Modes of Operation: Methods and Techniques - :author: NIST - :publication: December 2001 - :url: doi.org/10.6028/NIST.SP.800-38A + :title: Special Publication 800-38A: Recommendation for Block Cipher Modes of Operation: Methods and Techniques + :author: NIST + :publication: December 2001 + :url: doi.org/10.6028/NIST.SP.800-38A .. reference:: SP800-38B - :title: NIST Special Publication 800-38B: Recommendation for Block Cipher Modes of Operation: the CMAC Mode for Authentication - :author: NIST - :publication: May 2005 - :url: doi.org/10.6028/NIST.SP.800-38B + :title: Special Publication 800-38B: Recommendation for Block Cipher Modes of Operation: the CMAC Mode for Authentication + :author: NIST + :publication: May 2005 + :url: doi.org/10.6028/NIST.SP.800-38B .. reference:: SP800-38D - :title: NIST Special Publication 800-38D: Recommendation for Block Cipher Modes of Operation: Galois/Counter Mode (GCM) and GMAC - :author: NIST - :publication: November 2007 - :url: doi.org/10.6028/NIST.SP.800-38D + :title: Special Publication 800-38D: Recommendation for Block Cipher Modes of Operation: Galois/Counter Mode (GCM) and GMAC + :author: NIST + :publication: November 2007 + :url: doi.org/10.6028/NIST.SP.800-38D .. reference:: SP800-56A - :title: NIST Special Publication 800-56A: Recommendation for Pair-Wise Key-Establishment Schemes Using Discrete Logarithm Cryptography - :author: NIST - :publication: April 2018 - :url: doi.org/10.6028/NIST.SP.800-56Ar3 + :title: Special Publication 800-56A: Recommendation for Pair-Wise Key-Establishment Schemes Using Discrete Logarithm Cryptography + :author: NIST + :publication: April 2018 + :url: doi.org/10.6028/NIST.SP.800-56Ar3 .. reference:: SP800-67 - :title: NIST Special Publication 800-67: Recommendation for the Triple Data Encryption Algorithm (TDEA) Block Cipher - :author: NIST - :publication: November 2017 - :url: doi.org/10.6028/NIST.SP.800-67r2 + :title: Special Publication 800-67: Recommendation for the Triple Data Encryption Algorithm (TDEA) Block Cipher + :author: NIST + :publication: November 2017 + :url: doi.org/10.6028/NIST.SP.800-67r2 .. reference:: SP800-108 - :title: NIST Special Publication 800-108r1: Recommendation for Key Derivation Using Pseudorandom Functions - :author: NIST - :publication: August 2022 - :url: doi.org/10.6028/NIST.SP.800-108r1 + :title: Special Publication 800-108r1: Recommendation for Key Derivation Using Pseudorandom Functions + :author: NIST + :publication: August 2022 + :url: doi.org/10.6028/NIST.SP.800-108r1 .. reference:: SP800-232 - :title: NIST Special Publication 800-232: Ascon-Based Lightweight Cryptography Standards for Constrained Devices - :author: NIST - :publication: August 2025 - :url: doi.org/10.6028/NIST.SP.800-232 - -.. reference:: RFC1319 - :title: The MD2 Message-Digest Algorithm - :author: IETF - :publication: April 1992 - :url: tools.ietf.org/html/rfc1319.html - -.. reference:: RFC1320 - :title: The MD4 Message-Digest Algorithm - :author: IETF - :publication: April 1992 - :url: tools.ietf.org/html/rfc1320.html - -.. reference:: RFC1321 - :title: The MD5 Message-Digest Algorithm - :author: IETF - :publication: April 1992 - :url: tools.ietf.org/html/rfc1321.html - -.. reference:: RFC2104 - :title: HMAC: Keyed-Hashing for Message Authentication - :author: IETF - :publication: February 1997 - :url: tools.ietf.org/html/rfc2104.html - -.. reference:: RFC2315 - :title: PKCS #7: Cryptographic Message Syntax Version 1.5 - :author: IETF - :publication: March 1998 - :url: tools.ietf.org/html/rfc2315.html - -.. reference:: RFC3279 - :title: Algorithms and Identifiers for the Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile - :author: IETF - :publication: April 2002 - :url: tools.ietf.org/html/rfc3279.html - -.. reference:: RFC3610 - :title: Counter with CBC-MAC (CCM) - :author: IETF - :publication: September 2003 - :url: tools.ietf.org/html/rfc3610 - -.. reference:: RFC3713 - :title: A Description of the Camellia Encryption Algorithm - :author: IETF - :publication: April 2004 - :url: tools.ietf.org/html/rfc3713 - -.. reference:: RFC4279 - :title: Pre-Shared Key Ciphersuites for Transport Layer Security (TLS) - :author: IETF - :publication: December 2005 - :url: tools.ietf.org/html/rfc4279.html - -.. reference:: RFC4615 - :title: The Advanced Encryption Standard-Cipher-based Message Authentication Code-Pseudo-Random Function-128 (AES-CMAC-PRF-128) Algorithm for the Internet Key Exchange Protocol (IKE) - :author: IETF - :publication: August 2006 - :url: tools.ietf.org/html/rfc4615.html - -.. reference:: RFC5116 - :title: An Interface and Algorithms for Authenticated Encryption - :author: IETF - :publication: January 2008 - :url: tools.ietf.org/html/rfc5116.html - -.. reference:: RFC5246 - :title: The Transport Layer Security (TLS) Protocol Version 1.2 - :author: IETF - :publication: August 2008 - :url: tools.ietf.org/html/rfc5246.html - -.. reference:: RFC5489 - :title: ECDHE_PSK Cipher Suites for Transport Layer Security (TLS) - :author: IETF - :publication: March 2009 - :url: tools.ietf.org/html/rfc5489.html - -.. reference:: RFC5639 - :title: Elliptic Curve Cryptography (ECC) Brainpool Standard Curves and Curve Generation - :author: IETF - :publication: March 2010 - :url: tools.ietf.org/html/rfc5639.html - -.. reference:: RFC5794 - :title: A Description of the ARIA Encryption Algorithm - :author: IETF - :publication: March 2010 - :url: datatracker.ietf.org/doc/html/rfc5794 - -.. reference:: RFC5869 - :title: HMAC-based Extract-and-Expand Key Derivation Function (HKDF) - :author: IETF - :publication: May 2010 - :url: tools.ietf.org/html/rfc5869.html - -.. reference:: RFC5915 - :title: Elliptic Curve Private Key Structure - :author: IETF - :publication: June 2010 - :url: tools.ietf.org/html/rfc5915.html - -.. reference:: RFC6979 - :title: Deterministic Usage of the Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA) - :author: IETF - :publication: August 2013 - :url: tools.ietf.org/html/rfc6979.html - -.. reference:: RFC7748 - :title: Elliptic Curves for Security - :author: IETF - :publication: January 2016 - :url: tools.ietf.org/html/rfc7748.html - -.. reference:: RFC7919 - :title: Negotiated Finite Field Diffie-Hellman Ephemeral Parameters for Transport Layer Security (TLS) - :author: IETF - :publication: August 2016 - :url: tools.ietf.org/html/rfc7919.html - -.. reference:: RFC8017 - :title: PKCS #1: RSA Cryptography Specifications Version 2.2 - :author: IETF - :publication: November 2016 - :url: tools.ietf.org/html/rfc8017.html - -.. reference:: RFC8018 - :title: PKCS #5: Password-Based Cryptography Specification Version 2.1 - :author: IETF - :publication: January 2017 - :url: tools.ietf.org/html/rfc8018.html - -.. reference:: RFC8032 - :title: Edwards-Curve Digital Signature Algorithm (EdDSA) - :author: IRTF - :publication: January 2017 - :url: tools.ietf.org/html/rfc8032.html - -.. reference:: RFC8439 - :title: ChaCha20 and Poly1305 for IETF Protocols - :author: IRTF - :publication: June 2018 - :url: tools.ietf.org/html/rfc8439.html + :title: Special Publication 800-232: Ascon-Based Lightweight Cryptography Standards for Constrained Devices + :author: NIST + :publication: August 2025 + :url: doi.org/10.6028/NIST.SP.800-232 + +.. reference:: RFC 1319 + :title: The MD2 Message-Digest Algorithm + :author: IETF + :publication: April 1992 + :url: tools.ietf.org/html/rfc1319.html + +.. reference:: RFC 1320 + :title: The MD4 Message-Digest Algorithm + :author: IETF + :publication: April 1992 + :url: tools.ietf.org/html/rfc1320.html + +.. reference:: RFC 1321 + :title: The MD5 Message-Digest Algorithm + :author: IETF + :publication: April 1992 + :url: tools.ietf.org/html/rfc1321.html + +.. reference:: RFC 2104 + :title: HMAC: Keyed-Hashing for Message Authentication + :author: IETF + :publication: February 1997 + :url: tools.ietf.org/html/rfc2104.html + +.. reference:: RFC 2315 + :title: PKCS #7: Cryptographic Message Syntax Version 1.5 + :author: IETF + :publication: March 1998 + :url: tools.ietf.org/html/rfc2315.html + +.. reference:: RFC 3279 + :title: Algorithms and Identifiers for the Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile + :author: IETF + :publication: April 2002 + :url: tools.ietf.org/html/rfc3279.html + +.. reference:: RFC 3610 + :title: Counter with CBC-MAC (CCM) + :author: IETF + :publication: September 2003 + :url: tools.ietf.org/html/rfc3610 + +.. reference:: RFC 3713 + :title: A Description of the Camellia Encryption Algorithm + :author: IETF + :publication: April 2004 + :url: tools.ietf.org/html/rfc3713 + +.. reference:: RFC 4279 + :title: Pre-Shared Key Ciphersuites for Transport Layer Security (TLS) + :author: IETF + :publication: December 2005 + :url: tools.ietf.org/html/rfc4279.html + +.. reference:: RFC 4615 + :title: The Advanced Encryption Standard-Cipher-based Message Authentication Code-Pseudo-Random Function-128 (AES-CMAC-PRF-128) Algorithm for the Internet Key Exchange Protocol (IKE) + :author: IETF + :publication: August 2006 + :url: tools.ietf.org/html/rfc4615.html + +.. reference:: RFC 5116 + :title: An Interface and Algorithms for Authenticated Encryption + :author: IETF + :publication: January 2008 + :url: tools.ietf.org/html/rfc5116.html + +.. reference:: RFC 5246 + :title: The Transport Layer Security (TLS) Protocol Version 1.2 + :author: IETF + :publication: August 2008 + :url: tools.ietf.org/html/rfc5246.html + +.. reference:: RFC 5489 + :title: ECDHE_PSK Cipher Suites for Transport Layer Security (TLS) + :author: IETF + :publication: March 2009 + :url: tools.ietf.org/html/rfc5489.html + +.. reference:: RFC 5639 + :title: Elliptic Curve Cryptography (ECC) Brainpool Standard Curves and Curve Generation + :author: IETF + :publication: March 2010 + :url: tools.ietf.org/html/rfc5639.html + +.. reference:: RFC 5794 + :title: A Description of the ARIA Encryption Algorithm + :author: IETF + :publication: March 2010 + :url: datatracker.ietf.org/doc/html/rfc5794 + +.. reference:: RFC 5869 + :title: HMAC-based Extract-and-Expand Key Derivation Function (HKDF) + :author: IETF + :publication: May 2010 + :url: tools.ietf.org/html/rfc5869.html + +.. reference:: RFC 5915 + :title: Elliptic Curve Private Key Structure + :author: IETF + :publication: June 2010 + :url: tools.ietf.org/html/rfc5915.html + +.. reference:: RFC 6979 + :title: Deterministic Usage of the Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA) + :author: IETF + :publication: August 2013 + :url: tools.ietf.org/html/rfc6979.html + +.. reference:: RFC 7748 + :title: Elliptic Curves for Security + :author: IETF + :publication: January 2016 + :url: tools.ietf.org/html/rfc7748.html + +.. reference:: RFC 7919 + :title: Negotiated Finite Field Diffie-Hellman Ephemeral Parameters for Transport Layer Security (TLS) + :author: IETF + :publication: August 2016 + :url: tools.ietf.org/html/rfc7919.html + +.. reference:: RFC 8017 + :title: PKCS #1: RSA Cryptography Specifications Version 2.2 + :author: IETF + :publication: November 2016 + :url: tools.ietf.org/html/rfc8017.html + +.. reference:: RFC 8018 + :title: PKCS #5: Password-Based Cryptography Specification Version 2.1 + :author: IETF + :publication: January 2017 + :url: tools.ietf.org/html/rfc8018.html + +.. reference:: RFC 8032 + :title: Edwards-Curve Digital Signature Algorithm (EdDSA) + :author: IRTF + :publication: January 2017 + :url: tools.ietf.org/html/rfc8032.html + +.. reference:: RFC 8439 + :title: ChaCha20 and Poly1305 for IETF Protocols + :author: IRTF + :publication: June 2018 + :url: tools.ietf.org/html/rfc8439.html .. reference:: RIPEMD - :title: RIPEMD-160: A Strengthened Version of RIPEMD - :author: Dobbertin, Bosselaers and Preneel - :publication: April 1996 - :url: homes.esat.kuleuven.be/~bosselae/ripemd160.html + :title: RIPEMD-160: A Strengthened Version of RIPEMD + :author: Dobbertin, Bosselaers and Preneel + :publication: April 1996 + :url: homes.esat.kuleuven.be/~bosselae/ripemd160.html .. reference:: ISO9797 - :title: ISO/IEC 9797-1:2011 Information technology — Security techniques — Message Authentication Codes (MACs) — Part 1: Mechanisms using a block cipher - :author: ISO/IEC - :publication: March 2011 - :url: www.iso.org/standard/50375.html + :title: Information technology — Security techniques — Message Authentication Codes (MACs) — Part 1: Mechanisms using a block cipher + :doc_id: ISO/IEC 9797-1:2011 + :publication: March 2011 + :url: www.iso.org/standard/50375.html .. reference:: ISO10118 - :title: ISO/IEC 10118-3:2018 IT Security techniques — Hash-functions — Part 3: Dedicated hash-functions - :author: ISO/IEC - :publication: October 2018 - :url: www.iso.org/standard/67116.html + :title: IT Security techniques — Hash-functions — Part 3: Dedicated hash-functions + :doc_id: ISO/IEC 10118-3:2018 + :publication: October 2018 + :url: www.iso.org/standard/67116.html .. reference:: CSTC0002 - :title: GM/T 0002-2012: SM4 block cipher algorithm - :author: Cryptography Standardization Technical Committee - :publication: March 2012 + :title: SM4 block cipher algorithm + :doc_id: GM/T 0002-2012 + :author: Cryptography Standardization Technical Committee + :publication: March 2012 .. reference:: CSTC0004 - :title: GM/T 0004-2012: SM3 cryptographic hash algorithm - :author: Cryptography Standardization Technical Committee - :publication: March 2012 + :title: SM3 cryptographic hash algorithm + :doc_id: GM/T 0004-2012 + :author: Cryptography Standardization Technical Committee + :publication: March 2012 .. reference:: X9-62 - :title: Public Key Cryptography For The Financial Services Industry: The Elliptic Curve Digital Signature Algorithm (ECDSA) - :author: ANSI - :url: standards.globalspec.com/std/1955141/ANSI%20X9.62 + :title: Public Key Cryptography For The Financial Services Industry: The Elliptic Curve Digital Signature Algorithm (ECDSA) + :doc_id: ANSI X9-62 + :url: standards.globalspec.com/std/1955141/ANSI%20X9.62 .. reference:: CHACHA20 - :author: Bernstein, D. - :title: ChaCha, a variant of Salsa20 - :url: http://cr.yp.to/chacha/chacha-20080128.pdf - :publication: January 2008 + :author: Bernstein, D. + :title: ChaCha, a variant of Salsa20 + :url: http://cr.yp.to/chacha/chacha-20080128.pdf + :publication: January 2008 .. reference:: XCHACHA - :title: XChaCha: eXtended-nonce ChaCha and AEAD_XChaCha20_Poly1305 - :author: Arciszewski - :publication: January 2020 - :url: datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha-03 + :title: XChaCha: eXtended-nonce ChaCha and AEAD_XChaCha20_Poly1305 + :author: Arciszewski + :publication: January 2020 + :url: datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha-03 .. reference:: CLULOW - :author: Clulow, Jolyon - :title: On the Security of PKCS #11 - :url: link.springer.com/chapter/10.1007/978-3-540-45238-6_32 - :publication: 2003 + :author: Clulow, Jolyon + :title: On the Security of PKCS #11 + :kind: informative + :url: link.springer.com/chapter/10.1007/978-3-540-45238-6_32 + :publication: 2003 .. reference:: TLS-ECJPAKE - :title: Elliptic Curve J-PAKE Cipher Suites for Transport Layer Security (TLS) - :author: Cragie, Hao - :publication: June 2016 - :url: datatracker.ietf.org/doc/html/draft-cragie-tls-ecjpake-01 + :title: Elliptic Curve J-PAKE Cipher Suites for Transport Layer Security (TLS) + :author: Cragie, Hao + :publication: June 2016 + :url: datatracker.ietf.org/doc/html/draft-cragie-tls-ecjpake-01 .. reference:: ZIGBEE - :author: zigbee alliance - :title: zigbee Specification - :url: csa-iot.org/wp-content/uploads/2022/01/docs-05-3474-22-0csg-zigbee-specification-1.pdf - :publication: April 2017 + :title: zigbee Specification + :doc_id: zigbee 05-3474-22 + :url: csa-iot.org/wp-content/uploads/2022/01/docs-05-3474-22-0csg-zigbee-specification-1.pdf + :publication: April 2017 .. reference:: IEEE-CCM - :author: IEEE - :title: IEEE Standard for Low-Rate Wireless Networks - :url: standards.ieee.org/ieee/802.15.4/7029/ - :publication: 2020 + :title: IEEE Standard for Low-Rate Wireless Networks + :doc_id: IEEE 802.15.4-2020 + :url: standards.ieee.org/ieee/802.15.4/7029/ + :publication: 2020 .. reference:: MATTER - :title: Matter Specification, Version 1.2 - :author: CSA - :publication: October 2023 - :url: csa-iot.org/all-solutions/matter/ - -.. reference:: RFC8235 - :title: Schnorr Non-interactive Zero-Knowledge Proof - :author: IETF - :publication: September 2017 - :url: tools.ietf.org/html/rfc8235.html - -.. reference:: RFC8236 - :title: J-PAKE: Password-Authenticated Key Exchange by Juggling - :author: IETF - :publication: September 2017 - :url: tools.ietf.org/html/rfc8236.html - -.. reference:: RFC9383 - :title: SPAKE2+, an Augmented Password-Authenticated Key Exchange (PAKE) Protocol - :author: IETF - :publication: September 2023 - :url: tools.ietf.org/html/rfc9383.html + :title: Matter Specification, Version 1.2 + :author: CSA + :publication: October 2023 + :url: csa-iot.org/all-solutions/matter/ + +.. reference:: RFC 8235 + :title: Schnorr Non-interactive Zero-Knowledge Proof + :author: IETF + :publication: September 2017 + :url: tools.ietf.org/html/rfc8235.html + +.. reference:: RFC 8236 + :title: J-PAKE: Password-Authenticated Key Exchange by Juggling + :author: IETF + :publication: September 2017 + :url: tools.ietf.org/html/rfc8236.html + +.. reference:: RFC 9383 + :title: SPAKE2+, an Augmented Password-Authenticated Key Exchange (PAKE) Protocol + :author: IETF + :publication: September 2023 + :url: tools.ietf.org/html/rfc9383.html .. reference:: SPAKE2P-2 - :title: SPAKE2+, an Augmented PAKE (Draft 02) - :author: IETF - :publication: December 2020 - :url: datatracker.ietf.org/doc/draft-bar-cfrg-spake2plus-02 + :title: SPAKE2+, an Augmented PAKE (Draft 02) + :author: IETF + :publication: December 2020 + :url: datatracker.ietf.org/doc/draft-bar-cfrg-spake2plus-02 .. reference:: THREAD - :title: Thread Specification 1.3.0 - :author: Thread Group - :publication: July 2022 - :url: www.threadgroup.org/ThreadSpec - -.. reference:: PSA-PQC - :title: PSA Certified Crypto API 1.4 PQC Extension - :doc_no: ARM AES 0119 - :url: arm-software.github.io/psa-api/crypto - -.. reference:: RFC5958 - :title: Asymmetric Key Packages - :author: IETF - :publication: August 2010 - :url: tools.ietf.org/html/rfc5958.html - -.. reference:: RFC3394 - :title: Advanced Encryption Standard (AES) Key Wrap Algorithm - :author: IETF - :publication: September 2002 - :url: tools.ietf.org/html/rfc3394.html - -.. reference:: RFC5649 - :title: Advanced Encryption Standard (AES) Key Wrap with Padding Algorithm - :author: IETF - :publication: August 2009 - :url: tools.ietf.org/html/rfc5649.html + :title: Thread Specification 1.3.0 + :author: Thread Group + :publication: July 2022 + :url: www.threadgroup.org/ThreadSpec + +.. reference:: PSA PQC + :title: PSA Certified Crypto API 1.4 PQC Extension + :doc_id: Arm AES 0119 + :url: arm-software.github.io/psa-api/crypto + +.. reference:: RFC 5958 + :title: Asymmetric Key Packages + :kind: informative + :author: IETF + :publication: August 2010 + :url: tools.ietf.org/html/rfc5958.html + +.. reference:: RFC 3394 + :title: Advanced Encryption Standard (AES) Key Wrap Algorithm + :author: IETF + :publication: September 2002 + :url: tools.ietf.org/html/rfc3394.html + +.. reference:: RFC 5649 + :title: Advanced Encryption Standard (AES) Key Wrap with Padding Algorithm + :author: IETF + :publication: August 2009 + :url: tools.ietf.org/html/rfc5649.html .. reference:: SP800-38F - :title: NIST Special Publication 800-38F: Recommendation for Block Cipher Modes of Operation: Methods for Key Wrapping - :author: NIST - :publication: December 2012 - :url: doi.org/10.6028/NIST.SP.800-38F + :title: NIST Special Publication 800-38F: Recommendation for Block Cipher Modes of Operation: Methods for Key Wrapping + :author: NIST + :publication: December 2012 + :url: doi.org/10.6028/NIST.SP.800-38F -.. reference:: RFC3526 - :title: More Modular Exponential (MODP) Diffie-Hellman groups for Internet Key Exchange (IKE) - :author: IETF - :publication: May 2003 - :url: tools.ietf.org/html/rfc3526.html +.. reference:: RFC 3526 + :title: More Modular Exponential (MODP) Diffie-Hellman groups for Internet Key Exchange (IKE) + :author: IETF + :publication: May 2003 + :url: tools.ietf.org/html/rfc3526.html .. reference:: IEEE-802.11 - :title: IEEE 802.11-2024: Wireless LAN Medium Access Control (MAC) and Physical Layer (PHY) Specifications - :author: IEEE - :publication: 2024 - :url: standards.ieee.org/ieee/802.11/10548/ + :title: Wireless LAN Medium Access Control (MAC) and Physical Layer (PHY) Specifications + :doc_id: IEEE 802.11:2024 + :publication: 2024 + :url: standards.ieee.org/ieee/802.11/10548/ .. reference:: MailTrusT - :title: MailTrusT Version 2 Algorithmen - :author: TeleTrusT - :publication: March 1999 - :url: www.teletrust.de/fileadmin/files/ag8_mttv2-6.pdf + :title: MailTrusT Version 2 Algorithmen + :author: TeleTrusT + :publication: March 1999 + :url: www.teletrust.de/fileadmin/files/ag8_mttv2-6.pdf .. reference:: SM3-draft - :title: The SM3 Cryptographic Hash Function (Draft 02) - :author: Sean Shen, XiaoDong Lee, Ronald Henry Tse, Wong Wai Kit, Paul Yang - :publication: July 2018 - :url: datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3-02 - -.. reference:: RFC9688 - :title: Use of the SHA3 One-Way Hash Functions in the Cryptographic Message Syntax (CMS) - :author: IETF - :publication: November 2024 - :url: tools.ietf.org/html/rfc9688.html + :title: The SM3 Cryptographic Hash Function (Draft 02) + :kind: informative + :author: Sean Shen, XiaoDong Lee, Ronald Henry Tse, Wong Wai Kit, Paul Yang + :publication: July 2018 + :url: datatracker.ietf.org/doc/html/draft-sca-cfrg-sm3-02 + +.. reference:: RFC 9688 + :title: Use of the SHA3 One-Way Hash Functions in the Cryptographic Message Syntax (CMS) + :author: IETF + :publication: November 2024 + :url: tools.ietf.org/html/rfc9688.html .. reference:: FIPS203 - :title: FIPS Publication 203: Module-Lattice-Based Key-Encapsulation Mechanism Standard - :author: NIST - :publication: August 2024 - :url: doi.org/10.6028/NIST.FIPS.203 + :title: FIPS Publication 203: Module-Lattice-Based Key-Encapsulation Mechanism Standard + :doc_id: FIPS 203 + :author: NIST + :publication: August 2024 + :url: doi.org/10.6028/NIST.FIPS.203 .. reference:: FIPS204 - :title: FIPS Publication 204: Module-Lattice-Based Digital Signature Standard - :author: NIST - :publication: August 2024 - :url: doi.org/10.6028/NIST.FIPS.204 + :title: FIPS Publication 204: Module-Lattice-Based Digital Signature Standard + :doc_id: FIPS 204 + :author: NIST + :publication: August 2024 + :url: doi.org/10.6028/NIST.FIPS.204 .. reference:: FIPS205 - :title: FIPS Publication 205: Stateless Hash-Based Digital Signature Standard - :author: NIST - :publication: August 2024 - :url: doi.org/10.6028/NIST.FIPS.205 - -.. reference:: RFC9935 - :title: Internet X.509 Public Key Infrastructure - Algorithm Identifiers for Module-Lattice-Based Key-Encapsulation Mechanism (ML-KEM) - :author: IETF - :publication: March 2026 - :url: tools.ietf.org/html/rfc9935 - -.. reference:: RFC9881 - :title: Internet X.509 Public Key Infrastructure --- Algorithm Identifiers for the Module-Lattice-Based Digital Signature Algorithm (ML-DSA) - :author: IETF - :publication: October 2025 - :url: tools.ietf.org/html/rfc9881 - -.. reference:: RFC9909 - :title: Internet X.509 Public Key Infrastructure --- Algorithm Identifiers for the Stateless Hash-Based Digital Signature Algorithm (SLH-DSA) - :author: IETF - :publication: December 2025 - :url: tools.ietf.org/html/rfc9909 + :title: FIPS Publication 205: Stateless Hash-Based Digital Signature Standard + :doc_id: FIPS 205 + :author: NIST + :publication: August 2024 + :url: doi.org/10.6028/NIST.FIPS.205 + +.. reference:: RFC 9935 + :title: Internet X.509 Public Key Infrastructure - Algorithm Identifiers for Module-Lattice-Based Key-Encapsulation Mechanism (ML-KEM) + :author: IETF + :publication: March 2026 + :url: tools.ietf.org/html/rfc9935 + +.. reference:: RFC 9881 + :title: Internet X.509 Public Key Infrastructure --- Algorithm Identifiers for the Module-Lattice-Based Digital Signature Algorithm (ML-DSA) + :author: IETF + :publication: October 2025 + :url: tools.ietf.org/html/rfc9881 + +.. reference:: RFC 9909 + :title: Internet X.509 Public Key Infrastructure --- Algorithm Identifiers for the Stateless Hash-Based Digital Signature Algorithm (SLH-DSA) + :author: IETF + :publication: December 2025 + :url: tools.ietf.org/html/rfc9909 .. reference:: NIST-PQC - :title: Post-Quantum Cryptography - :author: NIST - :publication: PQC Project page - :url: nist.gov/pqcrypto + :title: Post-Quantum Cryptography + :author: NIST + :publication: PQC Project page + :url: nist.gov/pqcrypto .. reference:: SP800-208 - :title: NIST Special Publication 800-208: Recommendation for Stateful Hash-Based Signature Schemes - :author: NIST - :publication: October 2020 - :url: doi.org/10.6028/NIST.SP.800-208 - -.. reference:: RFC8391 - :title: XMSS: eXtended Merkle Signature Scheme - :author: IRTF - :publication: May 2018 - :url: tools.ietf.org/html/rfc8391 - -.. reference:: RFC8554 - :title: Leighton-Micali Hash-Based Signatures - :author: IRTF - :publication: April 2019 - :url: tools.ietf.org/html/rfc8554 - -.. reference:: RFC9858 - :title: Additional Parameter sets for HSS/LMS Hash-Based Signatures - :author: IRTF - :publication: October 2025 - :url: tools.ietf.org/html/rfc9858 - -.. reference:: RFC9802 - :title: Use of the HSS and XMSS Hash-Based Signature Algorithms in Internet X.509 Public Key Infrastructure - :author: IETF - :publication: June 2025 - :url: tools.ietf.org/html/rfc9802 - -.. reference:: RFC8702 - :title: Use of the SHAKE One-Way Hash Functions in the Cryptographic Message Syntax (CMS) - :author: IETF - :publication: January 2020 - :url: tools.ietf.org/html/rfc8702.html - -.. reference:: RFC7693 - :title: The BLAKE2 Cryptographic Hash and Message Authentication Code (MAC) - :author: J-P. Aumasson, M-J. Saarinen - :publication: November 2015 - :url: tools.ietf.org/html/rfc7693.html + :title: NIST Special Publication 800-208: Recommendation for Stateful Hash-Based Signature Schemes + :author: NIST + :publication: October 2020 + :url: doi.org/10.6028/NIST.SP.800-208 + +.. reference:: RFC 8391 + :title: XMSS: eXtended Merkle Signature Scheme + :author: IRTF + :publication: May 2018 + :url: tools.ietf.org/html/rfc8391 + +.. reference:: RFC 8554 + :title: Leighton-Micali Hash-Based Signatures + :author: IRTF + :publication: April 2019 + :url: tools.ietf.org/html/rfc8554 + +.. reference:: RFC 9858 + :title: Additional Parameter sets for HSS/LMS Hash-Based Signatures + :author: IRTF + :publication: October 2025 + :url: tools.ietf.org/html/rfc9858 + +.. reference:: RFC 9802 + :title: Use of the HSS and XMSS Hash-Based Signature Algorithms in Internet X.509 Public Key Infrastructure + :author: IETF + :publication: June 2025 + :url: tools.ietf.org/html/rfc9802 + +.. reference:: RFC 8702 + :title: Use of the SHAKE One-Way Hash Functions in the Cryptographic Message Syntax (CMS) + :author: IETF + :publication: January 2020 + :url: tools.ietf.org/html/rfc8702.html + +.. reference:: RFC 7693 + :title: The BLAKE2 Cryptographic Hash and Message Authentication Code (MAC) + :author: J-P. Aumasson, M-J. Saarinen + :publication: November 2015 + :url: tools.ietf.org/html/rfc7693.html .. reference:: BLAKE2 - :title: BLAKE2: simpler, smaller, fast as MD5 - :author: Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O’Hearn, Christian Winnerlein - :publication: January 2013 - :url: blake2.net/blake2.pdf + :title: BLAKE2: simpler, smaller, fast as MD5 + :author: Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O’Hearn, Christian Winnerlein + :publication: January 2013 + :url: blake2.net/blake2.pdf diff --git a/doc/crypto/about/releases b/doc/crypto/about/releases index eb0a6df0..50ff2685 100644 --- a/doc/crypto/about/releases +++ b/doc/crypto/about/releases @@ -1,24 +1,6 @@ .. SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited and/or its affiliates .. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license -.. release:: 1.0 Beta 1 - :date: January 2019 - :confidentiality: Non-confidential - - First public beta release. - -.. release:: 1.0 Beta 2 - :date: February 2019 - :confidentiality: Non-confidential - - Update for release with other PSA Certified API specifications. - -.. release:: 1.0 Beta 3 - :date: May 2019 - :confidentiality: Non-confidential - - Update for release with other PSA Certified API specifications. - .. release:: 1.0 :date: February 2020 :confidentiality: Non-confidential @@ -110,3 +92,8 @@ Integrated the PQC extension. New algorithms for BLAKE2 and multi-part asymmetric signature operations. + +.. release-info:: + :extend: + + The detailed changes in each release are described in :secref:`changes`. diff --git a/doc/crypto/api/library/status.rst b/doc/crypto/api/library/status.rst index 40c55b6a..fc21af1e 100644 --- a/doc/crypto/api/library/status.rst +++ b/doc/crypto/api/library/status.rst @@ -1,4 +1,4 @@ -.. SPDX-FileCopyrightText: Copyright 2018-2025 Arm Limited and/or its affiliates +.. SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited and/or its affiliates .. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license .. _status-codes: @@ -8,7 +8,7 @@ Status codes The |API| uses the status code definitions that are shared with the other PSA Certified APIs. The |API| also provides some |API|-specific status codes, see :secref:`specific-errors`. -The following elements are defined in :file:`psa/error.h` from :cite-title:`PSA-STAT` (previously defined in :cite:`PSA-FFM`): +The following elements are defined in :file:`psa/error.h` from :cite-title:`PSA STAT`: .. code-block:: xref @@ -45,7 +45,7 @@ These definitions must be available to an application that includes the :file:`p Common error codes ^^^^^^^^^^^^^^^^^^ -Some of the common status codes have a more precise meaning when returned by a function in the |API|, compared to the definitions in `[PSA-STAT]`. See also :secref:`error-handling`. +Some of the common status codes have a more precise meaning when returned by a function in the |API|, compared to the definitions in `[PSA STAT]`. See also :secref:`error-handling`. .. list-table:: :class: longtable @@ -56,12 +56,12 @@ Some of the common status codes have a more precise meaning when returned by a f - Meaning in the |API| * - :code:`PSA_ERROR_NOT_SUPPORTED` - - `[PSA-STAT]` recommends the use of :code:`PSA_ERROR_INVALID_ARGUMENT` for invalid parameter values. + - `[PSA STAT]` recommends the use of :code:`PSA_ERROR_INVALID_ARGUMENT` for invalid parameter values. In the |API|, this is relaxed for algorithm identifier and key type parameters. It is recommended to return :code:`PSA_ERROR_INVALID_ARGUMENT` for invalid values, but :code:`PSA_ERROR_NOT_SUPPORTED` is also allowed, to permit implementations to avoid having to recognize all the cryptographic mechanisms that are defined in the PSA specification but not provided by that particular implementation. * - :code:`PSA_ERROR_INVALID_ARGUMENT` - - `[PSA-STAT]` recommends the use of :code:`PSA_ERROR_NOT_SUPPORTED` for unsupported parameter values. + - `[PSA STAT]` recommends the use of :code:`PSA_ERROR_NOT_SUPPORTED` for unsupported parameter values. In the |API|, either :code:`PSA_ERROR_INVALID_ARGUMENT` or :code:`PSA_ERROR_NOT_SUPPORTED` can be returned when unsupported algorithm identifier or key type parameters are used. This allows implementations to avoid having to recognize all the cryptographic mechanisms that are defined in the PSA specification but not provided by that particular implementation. diff --git a/doc/crypto/appendix/encodings.rst b/doc/crypto/appendix/encodings.rst index b40c57b3..0ceb7048 100644 --- a/doc/crypto/appendix/encodings.rst +++ b/doc/crypto/appendix/encodings.rst @@ -737,7 +737,7 @@ RFC3526 defines a set of FF groups that are recommended for use with WPA3-SAE (t :widths: auto WPA3-SAE suite, DH-FAMILY, P, DH family :sup:`a`, Key value - RFC3526, 0x02, 1, `PSA_DH_FAMILY_RFC3526`, ``0x3305`` + RFC 3526, 0x02, 1, `PSA_DH_FAMILY_RFC3526`, ``0x3305`` a. The finite field Diffie Hellman family values defined in the API also include the parity bit. The password token key type value is constructed from the finite field Diffie Hellman family using :code:`PSA_KEY_TYPE_WPA3_SAE_DH(family)`. @@ -895,7 +895,7 @@ The defined values for DH-FAMILY and P are shown in :numref:`table-dh-type`. :widths: auto DH key group, DH-FAMILY, P, DH family :sup:`a`, Public-key value, Key-pair value - RFC7919, 0x01, 1, `PSA_DH_FAMILY_RFC7919`, ``0x4203``, ``0x7203`` + RFC 7919, 0x01, 1, `PSA_DH_FAMILY_RFC7919`, ``0x4203``, ``0x7203`` a. The finite field Diffie Hellman group family values defined in the API also include the parity bit. The key type value is constructed from the finite field Diffie Hellman family using either :code:`PSA_KEY_TYPE_DH_PUBLIC_KEY(family)` or :code:`PSA_KEY_TYPE_DH_KEY_PAIR(family)` as required. diff --git a/doc/crypto/appendix/history.rst b/doc/crypto/appendix/history.rst index 73a2cf62..4dce0754 100644 --- a/doc/crypto/appendix/history.rst +++ b/doc/crypto/appendix/history.rst @@ -11,6 +11,16 @@ Document change history This section provides the detailed changes made between published version of the document. +Changes in the draft GlobalPlatform publication revision +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Other changes +~~~~~~~~~~~~~ + +* Migrated the document to the 2026 PSA Certified API template. + + This changes the document front matter structure and publication styling, without changing the API. + Changes between *1.4.1* and *1.5* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -31,7 +41,7 @@ Changes to the API Other changes ~~~~~~~~~~~~~ -* Integrated the PQC algorithms and key types from :cite-title:`PSA-PQC`. +* Integrated the PQC algorithms and key types from :cite-title:`PSA PQC`. This provides support for LMS, HSS, XMSS, |XMSS^MT|, ML-DSA, SLH-DSA, and ML-KEM. @@ -370,552 +380,7 @@ Other changes - Moved most introductory material from the :secref:`functionality-overview` into the relevant API sections. -Changes between *1.0 beta 3* and *1.0.0* -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Changes to the API -~~~~~~~~~~~~~~~~~~ - -* Added `PSA_CRYPTO_API_VERSION_MAJOR` and `PSA_CRYPTO_API_VERSION_MINOR` to report the |API| version. - -* Removed ``PSA_ALG_GMAC`` algorithm identifier. - -* Removed internal implementation macros from the API specification: - - - ``PSA_AEAD_TAG_LENGTH_OFFSET`` - - ``PSA_ALG_AEAD_FROM_BLOCK_FLAG`` - - ``PSA_ALG_AEAD_TAG_LENGTH_MASK`` - - ``PSA__ALG_AEAD_WITH_DEFAULT_TAG_LENGTH__CASE`` - - ``PSA_ALG_CATEGORY_AEAD`` - - ``PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION`` - - ``PSA_ALG_CATEGORY_CIPHER`` - - ``PSA_ALG_CATEGORY_HASH`` - - ``PSA_ALG_CATEGORY_KEY_AGREEMENT`` - - ``PSA_ALG_CATEGORY_KEY_DERIVATION`` - - ``PSA_ALG_CATEGORY_MAC`` - - ``PSA_ALG_CATEGORY_MASK`` - - ``PSA_ALG_CATEGORY_SIGN`` - - ``PSA_ALG_CIPHER_FROM_BLOCK_FLAG`` - - ``PSA_ALG_CIPHER_MAC_BASE`` - - ``PSA_ALG_CIPHER_STREAM_FLAG`` - - ``PSA_ALG_DETERMINISTIC_ECDSA_BASE`` - - ``PSA_ALG_ECDSA_BASE`` - - ``PSA_ALG_ECDSA_IS_DETERMINISTIC`` - - ``PSA_ALG_HASH_MASK`` - - ``PSA_ALG_HKDF_BASE`` - - ``PSA_ALG_HMAC_BASE`` - - ``PSA_ALG_IS_KEY_DERIVATION_OR_AGREEMENT`` - - ``PSA_ALG_IS_VENDOR_DEFINED`` - - ``PSA_ALG_KEY_AGREEMENT_MASK`` - - ``PSA_ALG_KEY_DERIVATION_MASK`` - - ``PSA_ALG_MAC_SUBCATEGORY_MASK`` - - ``PSA_ALG_MAC_TRUNCATION_MASK`` - - ``PSA_ALG_RSA_OAEP_BASE`` - - ``PSA_ALG_RSA_PKCS1V15_SIGN_BASE`` - - ``PSA_ALG_RSA_PSS_BASE`` - - ``PSA_ALG_TLS12_PRF_BASE`` - - ``PSA_ALG_TLS12_PSK_TO_MS_BASE`` - - ``PSA_ALG_VENDOR_FLAG`` - - ``PSA_BITS_TO_BYTES`` - - ``PSA_BYTES_TO_BITS`` - - ``PSA_ECDSA_SIGNATURE_SIZE`` - - ``PSA_HMAC_MAX_HASH_BLOCK_SIZE`` - - ``PSA_KEY_EXPORT_ASN1_INTEGER_MAX_SIZE`` - - ``PSA_KEY_EXPORT_DSA_KEY_PAIR_MAX_SIZE`` - - ``PSA_KEY_EXPORT_DSA_PUBLIC_KEY_MAX_SIZE`` - - ``PSA_KEY_EXPORT_ECC_KEY_PAIR_MAX_SIZE`` - - ``PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE`` - - ``PSA_KEY_EXPORT_RSA_KEY_PAIR_MAX_SIZE`` - - ``PSA_KEY_EXPORT_RSA_PUBLIC_KEY_MAX_SIZE`` - - ``PSA_KEY_TYPE_CATEGORY_FLAG_PAIR`` - - ``PSA_KEY_TYPE_CATEGORY_KEY_PAIR`` - - ``PSA_KEY_TYPE_CATEGORY_MASK`` - - ``PSA_KEY_TYPE_CATEGORY_PUBLIC_KEY`` - - ``PSA_KEY_TYPE_CATEGORY_RAW`` - - ``PSA_KEY_TYPE_CATEGORY_SYMMETRIC`` - - ``PSA_KEY_TYPE_DH_GROUP_MASK`` - - ``PSA_KEY_TYPE_DH_KEY_PAIR_BASE`` - - ``PSA_KEY_TYPE_DH_PUBLIC_KEY_BASE`` - - ``PSA_KEY_TYPE_ECC_CURVE_MASK`` - - ``PSA_KEY_TYPE_ECC_KEY_PAIR_BASE`` - - ``PSA_KEY_TYPE_ECC_PUBLIC_KEY_BASE`` - - ``PSA_KEY_TYPE_IS_VENDOR_DEFINED`` - - ``PSA_KEY_TYPE_VENDOR_FLAG`` - - ``PSA_MAC_TRUNCATED_LENGTH`` - - ``PSA_MAC_TRUNCATION_OFFSET`` - - ``PSA_ROUND_UP_TO_MULTIPLE`` - - ``PSA_RSA_MINIMUM_PADDING_SIZE`` - - ``PSA_VENDOR_ECC_MAX_CURVE_BITS`` - - ``PSA_VENDOR_RSA_MAX_KEY_BITS`` - -* Remove the definition of implementation-defined macros from the specification, and clarified the implementation requirements for these macros in :secref:`implementation-specific-macro`. - - - Macros with implementation-defined values are indicated by ``/* implementation-defined value */`` in the API prototype. - The implementation must provide the implementation. - - - Macros for algorithm and key type construction and inspection have specification-defined values. - This is indicated by ``/* specification-defined value */`` in the API prototype. - Example definitions of these macros is provided in :secref:`appendix-specdef-values`. - -* Changed the semantics of multi-part operations. - - - Formalize the standard pattern for multi-part operations. - - Require all errors to result in an error state, requiring a call to ``psa_xxx_abort()`` to reset the object. - - Define behavior in illegal and impossible operation states, and for copying and reusing operation objects. - - Although the API signatures have not changed, this change requires modifications to application flows that handle error conditions in multi-part operations. - -* Merge the key identifier and key handle concepts in the API. - - - Replaced all references to key handles with key identifiers, or something similar. - - Replaced all uses of ``psa_key_handle_t`` with `psa_key_id_t` in the API, and removes the ``psa_key_handle_t`` type. - - Removed ``psa_open_key`` and ``psa_close_key``. - - Added `PSA_KEY_ID_NULL` for the never valid zero key identifier. - - Document rules related to destroying keys whilst in use. - - Added the `PSA_KEY_USAGE_CACHE` usage flag and the related `psa_purge_key()` API. - - Added clarification about caching keys to non-volatile memory. - -* Renamed ``PSA_ALG_TLS12_PSK_TO_MS_MAX_PSK_LEN`` to `PSA_TLS12_PSK_TO_MS_PSK_MAX_SIZE`. - -* Relax definition of implementation-defined types. - - - This is indicated in the specification by ``/* implementation-defined type */`` in the type definition. - - The specification only defines the name of implementation-defined types, and does not require that the implementation is a C struct. - -* Zero-length keys are not permitted. Attempting to create one will now result in an error. - -* Relax the constraints on inputs to key derivation: - - - `psa_key_derivation_input_bytes()` can be used for secret input steps. This is necessary if a zero-length input is required by the application. - - `psa_key_derivation_input_key()` can be used for non-secret input steps. - -* Multi-part cipher operations now require that the IV is passed using `psa_cipher_set_iv()`, the option to provide this as part of the input to `psa_cipher_update()` has been removed. - - The format of the output from `psa_cipher_encrypt()`, and input to `psa_cipher_decrypt()`, is documented. - -* Support macros to calculate the size of output buffers, IVs and nonces. - - - Macros to calculate a key and/or algorithm specific result are provided for all output buffers. The new macros are: - - * `PSA_AEAD_NONCE_LENGTH()` - * `PSA_CIPHER_ENCRYPT_OUTPUT_SIZE()` - * `PSA_CIPHER_DECRYPT_OUTPUT_SIZE()` - * `PSA_CIPHER_UPDATE_OUTPUT_SIZE()` - * `PSA_CIPHER_FINISH_OUTPUT_SIZE()` - * `PSA_CIPHER_IV_LENGTH()` - * `PSA_EXPORT_PUBLIC_KEY_OUTPUT_SIZE()` - * `PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE()` - - - Macros that evaluate to a maximum type-independent buffer size are provided. The new macros are: - - * `PSA_AEAD_ENCRYPT_OUTPUT_MAX_SIZE()` - * `PSA_AEAD_DECRYPT_OUTPUT_MAX_SIZE()` - * `PSA_AEAD_UPDATE_OUTPUT_MAX_SIZE()` - * `PSA_AEAD_FINISH_OUTPUT_MAX_SIZE` - * `PSA_AEAD_VERIFY_OUTPUT_MAX_SIZE` - * `PSA_AEAD_NONCE_MAX_SIZE` - * `PSA_AEAD_TAG_MAX_SIZE` - * `PSA_ASYMMETRIC_ENCRYPT_OUTPUT_MAX_SIZE` - * `PSA_ASYMMETRIC_DECRYPT_OUTPUT_MAX_SIZE` - * `PSA_CIPHER_ENCRYPT_OUTPUT_MAX_SIZE()` - * `PSA_CIPHER_DECRYPT_OUTPUT_MAX_SIZE()` - * `PSA_CIPHER_UPDATE_OUTPUT_MAX_SIZE()` - * `PSA_CIPHER_FINISH_OUTPUT_MAX_SIZE` - * `PSA_CIPHER_IV_MAX_SIZE` - * `PSA_EXPORT_KEY_PAIR_MAX_SIZE` - * `PSA_EXPORT_PUBLIC_KEY_MAX_SIZE` - * `PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE` - - - AEAD output buffer size macros are now parameterized on the key type as well as the algorithm: - - * `PSA_AEAD_ENCRYPT_OUTPUT_SIZE()` - * `PSA_AEAD_DECRYPT_OUTPUT_SIZE()` - * `PSA_AEAD_UPDATE_OUTPUT_SIZE()` - * `PSA_AEAD_FINISH_OUTPUT_SIZE()` - * `PSA_AEAD_TAG_LENGTH()` - * `PSA_AEAD_VERIFY_OUTPUT_SIZE()` - - - Some existing macros have been renamed to ensure that the name of the support macros are consistent. The following macros have been renamed: - - * ``PSA_ALG_AEAD_WITH_DEFAULT_TAG_LENGTH()`` → `PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG()` - * ``PSA_ALG_AEAD_WITH_TAG_LENGTH()`` → `PSA_ALG_AEAD_WITH_SHORTENED_TAG()` - * ``PSA_KEY_EXPORT_MAX_SIZE()`` → `PSA_EXPORT_KEY_OUTPUT_SIZE()` - * ``PSA_HASH_SIZE()`` → `PSA_HASH_LENGTH()` - * ``PSA_MAC_FINAL_SIZE()`` → `PSA_MAC_LENGTH()` - * ``PSA_BLOCK_CIPHER_BLOCK_SIZE()`` → `PSA_BLOCK_CIPHER_BLOCK_LENGTH()` - * ``PSA_MAX_BLOCK_CIPHER_BLOCK_SIZE`` → `PSA_BLOCK_CIPHER_BLOCK_MAX_SIZE` - - - Documentation of the macros and of related APIs has been updated to reference the related API elements. - -* Provide hash-and-sign operations as well as sign-the-hash operations. The API for asymmetric signature has been changed to clarify the use of the new functions. - - - The existing asymmetric signature API has been renamed to clarify that this is for signing a hash that is already computed: - - * ``PSA_KEY_USAGE_SIGN`` → `PSA_KEY_USAGE_SIGN_HASH` - * ``PSA_KEY_USAGE_VERIFY`` → `PSA_KEY_USAGE_VERIFY_HASH` - * ``psa_asymmetric_sign()`` → `psa_sign_hash()` - * ``psa_asymmetric_verify()`` → `psa_verify_hash()` - - - New APIs added to provide the complete message signing operation: - - * `PSA_KEY_USAGE_SIGN_MESSAGE` - * `PSA_KEY_USAGE_VERIFY_MESSAGE` - * `psa_sign_message()` - * `psa_verify_message()` - - - New Support macros to identify which algorithms can be used in which signing API: - - * `PSA_ALG_IS_SIGN_HASH()` - * `PSA_ALG_IS_SIGN_MESSAGE()` - - - Renamed support macros that apply to both signing APIs: - - * ``PSA_ASYMMETRIC_SIGN_OUTPUT_SIZE()`` → `PSA_SIGN_OUTPUT_SIZE()` - * ``PSA_ASYMMETRIC_SIGNATURE_MAX_SIZE`` → `PSA_SIGNATURE_MAX_SIZE` - - - The usage flag values have been changed, including for `PSA_KEY_USAGE_DERIVE`. - -* Restructure `psa_key_type_t` and reassign all key type values. - - - `psa_key_type_t` changes from 32-bit to 16-bit integer. - - Reassigned the key type categories. - - Add a parity bit to the key type to ensure that valid key type values differ by at least 2 bits. - - 16-bit elliptic curve ids (``psa_ecc_curve_t``) replaced by 8-bit ECC curve family ids (`psa_ecc_family_t`). - 16-bit Diffie-Hellman group ids (``psa_dh_group_t``) replaced by 8-bit DH group family ids (`psa_dh_family_t`). - - * These ids are no longer related to the IANA Group Registry specification. - * The new key type values do not encode the key size for ECC curves or DH groups. The key bit size from the key attributes identify a specific ECC curve or DH group within the family. - - - The following macros have been removed: - - * ``PSA_DH_GROUP_FFDHE2048`` - * ``PSA_DH_GROUP_FFDHE3072`` - * ``PSA_DH_GROUP_FFDHE4096`` - * ``PSA_DH_GROUP_FFDHE6144`` - * ``PSA_DH_GROUP_FFDHE8192`` - * ``PSA_ECC_CURVE_BITS`` - * ``PSA_ECC_CURVE_BRAINPOOL_P256R1`` - * ``PSA_ECC_CURVE_BRAINPOOL_P384R1`` - * ``PSA_ECC_CURVE_BRAINPOOL_P512R1`` - * ``PSA_ECC_CURVE_CURVE25519`` - * ``PSA_ECC_CURVE_CURVE448`` - * ``PSA_ECC_CURVE_SECP160K1`` - * ``PSA_ECC_CURVE_SECP160R1`` - * ``PSA_ECC_CURVE_SECP160R2`` - * ``PSA_ECC_CURVE_SECP192K1`` - * ``PSA_ECC_CURVE_SECP192R1`` - * ``PSA_ECC_CURVE_SECP224K1`` - * ``PSA_ECC_CURVE_SECP224R1`` - * ``PSA_ECC_CURVE_SECP256K1`` - * ``PSA_ECC_CURVE_SECP256R1`` - * ``PSA_ECC_CURVE_SECP384R1`` - * ``PSA_ECC_CURVE_SECP521R1`` - * ``PSA_ECC_CURVE_SECT163K1`` - * ``PSA_ECC_CURVE_SECT163R1`` - * ``PSA_ECC_CURVE_SECT163R2`` - * ``PSA_ECC_CURVE_SECT193R1`` - * ``PSA_ECC_CURVE_SECT193R2`` - * ``PSA_ECC_CURVE_SECT233K1`` - * ``PSA_ECC_CURVE_SECT233R1`` - * ``PSA_ECC_CURVE_SECT239K1`` - * ``PSA_ECC_CURVE_SECT283K1`` - * ``PSA_ECC_CURVE_SECT283R1`` - * ``PSA_ECC_CURVE_SECT409K1`` - * ``PSA_ECC_CURVE_SECT409R1`` - * ``PSA_ECC_CURVE_SECT571K1`` - * ``PSA_ECC_CURVE_SECT571R1`` - * ``PSA_KEY_TYPE_GET_CURVE`` - * ``PSA_KEY_TYPE_GET_GROUP`` - - - The following macros have been added: - - * `PSA_DH_FAMILY_RFC7919` - * `PSA_ECC_FAMILY_BRAINPOOL_P_R1` - * `PSA_ECC_FAMILY_SECP_K1` - * `PSA_ECC_FAMILY_SECP_R1` - * `PSA_ECC_FAMILY_SECP_R2` - * `PSA_ECC_FAMILY_SECT_K1` - * `PSA_ECC_FAMILY_SECT_R1` - * `PSA_ECC_FAMILY_SECT_R2` - * `PSA_ECC_FAMILY_MONTGOMERY` - * `PSA_KEY_TYPE_DH_GET_FAMILY` - * `PSA_KEY_TYPE_ECC_GET_FAMILY` - - - The following macros have new values: - - * `PSA_KEY_TYPE_AES` - * `PSA_KEY_TYPE_ARC4` - * `PSA_KEY_TYPE_CAMELLIA` - * `PSA_KEY_TYPE_CHACHA20` - * `PSA_KEY_TYPE_DERIVE` - * `PSA_KEY_TYPE_DES` - * `PSA_KEY_TYPE_HMAC` - * `PSA_KEY_TYPE_NONE` - * `PSA_KEY_TYPE_RAW_DATA` - * `PSA_KEY_TYPE_RSA_KEY_PAIR` - * `PSA_KEY_TYPE_RSA_PUBLIC_KEY` - - - The following macros with specification-defined values have new example implementations: - - * `PSA_BLOCK_CIPHER_BLOCK_LENGTH` - * `PSA_KEY_TYPE_DH_KEY_PAIR` - * `PSA_KEY_TYPE_DH_PUBLIC_KEY` - * `PSA_KEY_TYPE_ECC_KEY_PAIR` - * `PSA_KEY_TYPE_ECC_PUBLIC_KEY` - * `PSA_KEY_TYPE_IS_ASYMMETRIC` - * `PSA_KEY_TYPE_IS_DH` - * `PSA_KEY_TYPE_IS_DH_KEY_PAIR` - * `PSA_KEY_TYPE_IS_DH_PUBLIC_KEY` - * `PSA_KEY_TYPE_IS_ECC` - * `PSA_KEY_TYPE_IS_ECC_KEY_PAIR` - * `PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY` - * `PSA_KEY_TYPE_IS_KEY_PAIR` - * `PSA_KEY_TYPE_IS_PUBLIC_KEY` - * `PSA_KEY_TYPE_IS_RSA` - * `PSA_KEY_TYPE_IS_UNSTRUCTURED` - * `PSA_KEY_TYPE_KEY_PAIR_OF_PUBLIC_KEY` - * `PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR` - -* Add ECC family `PSA_ECC_FAMILY_FRP` for the FRP256v1 curve. - -* Restructure `psa_algorithm_t` encoding, to increase consistency across algorithm categories. - - - Algorithms that include a hash operation all use the same structure to encode the hash algorithm. The following ``PSA_ALG_XXXX_GET_HASH()`` macros have all been replaced by a single macro `PSA_ALG_GET_HASH()`: - - * ``PSA_ALG_HKDF_GET_HASH()`` - * ``PSA_ALG_HMAC_GET_HASH()`` - * ``PSA_ALG_RSA_OAEP_GET_HASH()`` - * ``PSA_ALG_SIGN_GET_HASH()`` - * ``PSA_ALG_TLS12_PRF_GET_HASH()`` - * ``PSA_ALG_TLS12_PSK_TO_MS_GET_HASH()`` - - - Stream cipher algorithm macros have been removed; the key type indicates which cipher to use. Instead of ``PSA_ALG_ARC4`` and ``PSA_ALG_CHACHA20``, use `PSA_ALG_STREAM_CIPHER`. - - All of the other ``PSA_ALG_XXX`` macros have updated values or updated example implementations. - - - The following macros have new values: - - * `PSA_ALG_ANY_HASH` - * `PSA_ALG_CBC_MAC` - * `PSA_ALG_CBC_NO_PADDING` - * `PSA_ALG_CBC_PKCS7` - * `PSA_ALG_CCM` - * `PSA_ALG_CFB` - * `PSA_ALG_CHACHA20_POLY1305` - * `PSA_ALG_CMAC` - * `PSA_ALG_CTR` - * `PSA_ALG_ECDH` - * `PSA_ALG_ECDSA_ANY` - * `PSA_ALG_FFDH` - * `PSA_ALG_GCM` - * `PSA_ALG_MD2` - * `PSA_ALG_MD4` - * `PSA_ALG_MD5` - * `PSA_ALG_OFB` - * `PSA_ALG_RIPEMD160` - * `PSA_ALG_RSA_PKCS1V15_CRYPT` - * `PSA_ALG_RSA_PKCS1V15_SIGN_RAW` - * `PSA_ALG_SHA_1` - * `PSA_ALG_SHA_224` - * `PSA_ALG_SHA_256` - * `PSA_ALG_SHA_384` - * `PSA_ALG_SHA_512` - * `PSA_ALG_SHA_512_224` - * `PSA_ALG_SHA_512_256` - * `PSA_ALG_SHA3_224` - * `PSA_ALG_SHA3_256` - * `PSA_ALG_SHA3_384` - * `PSA_ALG_SHA3_512` - * `PSA_ALG_XTS` - - - The following macros with specification-defined values have new example implementations: - - * `PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG()` - * `PSA_ALG_AEAD_WITH_SHORTENED_TAG()` - * `PSA_ALG_DETERMINISTIC_ECDSA()` - * `PSA_ALG_ECDSA()` - * `PSA_ALG_FULL_LENGTH_MAC()` - * `PSA_ALG_HKDF()` - * `PSA_ALG_HMAC()` - * `PSA_ALG_IS_AEAD()` - * `PSA_ALG_IS_AEAD_ON_BLOCK_CIPHER()` - * `PSA_ALG_IS_ASYMMETRIC_ENCRYPTION()` - * `PSA_ALG_IS_BLOCK_CIPHER_MAC()` - * `PSA_ALG_IS_CIPHER()` - * `PSA_ALG_IS_DETERMINISTIC_ECDSA()` - * `PSA_ALG_IS_ECDH()` - * `PSA_ALG_IS_ECDSA()` - * `PSA_ALG_IS_FFDH()` - * `PSA_ALG_IS_HASH()` - * `PSA_ALG_IS_HASH_AND_SIGN()` - * `PSA_ALG_IS_HKDF()` - * `PSA_ALG_IS_HMAC()` - * `PSA_ALG_IS_KEY_AGREEMENT()` - * `PSA_ALG_IS_KEY_DERIVATION()` - * `PSA_ALG_IS_MAC()` - * `PSA_ALG_IS_RANDOMIZED_ECDSA()` - * `PSA_ALG_IS_RAW_KEY_AGREEMENT()` - * `PSA_ALG_IS_RSA_OAEP()` - * `PSA_ALG_IS_RSA_PKCS1V15_SIGN()` - * `PSA_ALG_IS_RSA_PSS()` - * `PSA_ALG_IS_SIGN()` - * `PSA_ALG_IS_SIGN_MESSAGE()` - * `PSA_ALG_IS_STREAM_CIPHER()` - * `PSA_ALG_IS_TLS12_PRF()` - * `PSA_ALG_IS_TLS12_PSK_TO_MS()` - * `PSA_ALG_IS_WILDCARD()` - * `PSA_ALG_KEY_AGREEMENT()` - * `PSA_ALG_KEY_AGREEMENT_GET_BASE()` - * `PSA_ALG_KEY_AGREEMENT_GET_KDF()` - * `PSA_ALG_RSA_OAEP()` - * `PSA_ALG_RSA_PKCS1V15_SIGN()` - * `PSA_ALG_RSA_PSS()` - * `PSA_ALG_TLS12_PRF()` - * `PSA_ALG_TLS12_PSK_TO_MS()` - * `PSA_ALG_TRUNCATED_MAC()` - -* Added ECB block cipher mode, with no padding, as `PSA_ALG_ECB_NO_PADDING`. - -* Add functions to suspend and resume hash operations: - - - `psa_hash_suspend()` halts the current operation and outputs a hash suspend state. - - `psa_hash_resume()` continues a previously suspended hash operation. - - The format of the hash suspend state is documented in :secref:`hash-suspend-state`, and supporting macros are provided for using the |API|: - - - `PSA_HASH_SUSPEND_OUTPUT_SIZE()` - - `PSA_HASH_SUSPEND_OUTPUT_MAX_SIZE` - - `PSA_HASH_SUSPEND_ALGORITHM_FIELD_LENGTH` - - `PSA_HASH_SUSPEND_INPUT_LENGTH_FIELD_LENGTH()` - - `PSA_HASH_SUSPEND_HASH_STATE_FIELD_LENGTH()` - - `PSA_HASH_BLOCK_LENGTH()` - -* Complement :code:`PSA_ERROR_STORAGE_FAILURE` with new error codes :code:`PSA_ERROR_DATA_CORRUPT` and :code:`PSA_ERROR_DATA_INVALID`. These permit an implementation to distinguish different causes of failure when reading from key storage. - -* Added input step `PSA_KEY_DERIVATION_INPUT_CONTEXT` for key derivation, supporting obvious mapping from the step identifiers to common KDF constructions. - -Clarifications -~~~~~~~~~~~~~~ - -* Clarified rules regarding modification of parameters in concurrent environments. - -* Guarantee that :code:`psa_destroy_key(PSA_KEY_ID_NULL)` always returns :code:`PSA_SUCCESS`. - -* Clarified the TLS PSK to MS key-agreement algorithm. - -* Document the key policy requirements for all APIs that accept a key parameter. - -* Document more of the error codes for each function. - -Other changes -~~~~~~~~~~~~~ - -* Require C99 for this specification instead of C89. - -* Removed references to non-standard mbed-crypto header files. The only header file that applications need to include is :file:`psa/crypto.h`. - -* Reorganized the API reference, grouping the elements in a more natural way. - -* Improved the cross referencing between all of the document sections, and from code snippets to API element descriptions. - - -Changes between *1.0 beta 2* and *1.0 beta 3* -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Changes to the API -~~~~~~~~~~~~~~~~~~ - -* Change the value of error codes, and some names, to align - with other PSA Certified APIs. The name changes are: - - - :code:`PSA_ERROR_UNKNOWN_ERROR` → :code:`PSA_ERROR_GENERIC_ERROR` - - :code:`PSA_ERROR_OCCUPIED_SLOT` → :code:`PSA_ERROR_ALREADY_EXISTS` - - :code:`PSA_ERROR_EMPTY_SLOT` → :code:`PSA_ERROR_DOES_NOT_EXIST` - - :code:`PSA_ERROR_INSUFFICIENT_CAPACITY` → :code:`PSA_ERROR_INSUFFICIENT_DATA` - - :code:`PSA_ERROR_TAMPERING_DETECTED` → :code:`PSA_ERROR_CORRUPTION_DETECTED` - -* Change the way keys are created to avoid “half-filled” handles - that contained key metadata, but no key material. - Now, to create a key, first fill in a data structure containing - its attributes, then pass this structure to a function that - both allocates resources for the key and fills in the key - material. This affects the following functions: - - - `psa_import_key()`, `psa_generate_key()`, ``psa_generator_import_key()`` - and `psa_copy_key()` now take an attribute structure, as - a pointer to `psa_key_attributes_t`, to specify key metadata. - This replaces the previous method of passing arguments to - ``psa_create_key()`` or to the key material creation function - or calling ``psa_set_key_policy()``. - - ``psa_key_policy_t`` and functions operating on that type - no longer exist. A key's policy is now accessible as part of - its attributes. - - ``psa_get_key_information()`` is also replaced by accessing the - key's attributes, retrieved with `psa_get_key_attributes()`. - - ``psa_create_key()`` no longer exists. Instead, set the key id - attribute and the lifetime attribute before creating the - key material. - -* Allow `psa_aead_update()` to buffer data. - -* New buffer size calculation macros. - -* Key identifiers are no longer specific to a given lifetime value. ``psa_open_key()`` no longer takes a ``lifetime`` parameter. - -* Define a range of key identifiers for use by applications and a separate range for use by implementations. - -* Avoid the unusual terminology "generator": call them - "key-derivation operations" instead. Rename a number of functions - and other identifiers related to for clarity and consistency: - - - ``psa_crypto_generator_t`` → `psa_key_derivation_operation_t` - - ``PSA_CRYPTO_GENERATOR_INIT`` → `PSA_KEY_DERIVATION_OPERATION_INIT` - - ``psa_crypto_generator_init()`` → `psa_key_derivation_operation_init()` - - ``PSA_GENERATOR_UNBRIDLED_CAPACITY`` → `PSA_KEY_DERIVATION_UNLIMITED_CAPACITY` - - ``psa_set_generator_capacity()`` → `psa_key_derivation_set_capacity()` - - ``psa_get_generator_capacity()`` → `psa_key_derivation_get_capacity()` - - ``psa_key_agreement()`` → `psa_key_derivation_key_agreement()` - - ``psa_generator_read()`` → `psa_key_derivation_output_bytes()` - - ``psa_generate_derived_key()`` → `psa_key_derivation_output_key()` - - ``psa_generator_abort()`` → `psa_key_derivation_abort()` - - ``psa_key_agreement_raw_shared_secret()`` → `psa_raw_key_agreement()` - - ``PSA_KDF_STEP_xxx`` → ``PSA_KEY_DERIVATION_INPUT_xxx`` - - ``PSA_xxx_KEYPAIR`` → ``PSA_xxx_KEY_PAIR`` - -* Convert TLS1.2 KDF descriptions to multi-part key derivation. - -Clarifications -~~~~~~~~~~~~~~ - -* Specify ``psa_generator_import_key()`` for most key types. - -* Clarify the behavior in various corner cases. - -* Document more error conditions. - - - -Changes between *1.0 beta 1* and *1.0 beta 2* -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Changes to the API -~~~~~~~~~~~~~~~~~~ - -* Remove obsolete definition ``PSA_ALG_IS_KEY_SELECTION``. -* `PSA_AEAD_FINISH_OUTPUT_SIZE`: remove spurious parameter ``plaintext_length``. - -Clarifications -~~~~~~~~~~~~~~ - -* ``psa_key_agreement()``: document ``alg`` parameter. - -Other changes -~~~~~~~~~~~~~ - -* Document formatting improvements. - - -Planned changes for version |docversion|.x +Planned changes for version |APIversion|.x ------------------------------------------ Future versions of this specification that use a |docversion|.x version will describe the same API as this specification. diff --git a/doc/crypto/conf.py b/doc/crypto/conf.py index 37e72cd8..073241fc 100644 --- a/doc/crypto/conf.py +++ b/doc/crypto/conf.py @@ -8,7 +8,7 @@ doc_info = { # Document template - 'template': 'psa-api-2025', + 'template': 'psa-api-2026', # Document title, MANDATORY 'title': 'PSA Certified\nCrypto API', @@ -18,29 +18,21 @@ 'copyright_date': '2018-2026', 'copyright': 'Arm Limited and/or its affiliates', - # Arm document identifier, marked as open issue if not provided - 'doc_id': 'IHI 0086', + # Document identifier, marked as open issue if not provided + 'doc_id': 'GPD_SPE_086', # The short X.Y version. MANDATORY 'version': '1.5', - # Arm document quality status, marked as open issue if not provided - 'quality': 'REL', - # Arm document issue number (within that version and quality status) - # Marked as open issue if not provided + # Document maintenance revision 'issue_no': 0, - # Identifies the sequence number of a release candidate of the same issue - # default to None - #'release_candidate': 1, - # Draft status - use this to indicate the document is not ready for publication - #'draft': True, - - # Arm document confidentiality. Must be either Non-confidential or Confidential - # Marked as open issue if not provided - 'confidentiality': 'Non-confidential', + # Document draft revision + 'draft': 1, + # Document status + 'status': 'DFT', # Id of the legal notice for this document # Marked as open issue if not provided - 'license': 'psa-certified-api-license', + #'license': 'psa-certified-api-license', # Document date, default to build date 'date': 'June 2026', @@ -55,9 +47,6 @@ # 2 : Sub-elements of API - parameters, fields, values 'header_doxygen': 2, - # Declare a watermark for the PDF output - # 'watermark': 'DRAFT', - # Optional ordering of return error values # This list is used to create a standard ordering of return value responses # throughout the document, irrespective of their ordering in the source text @@ -99,14 +88,12 @@ 'prolog_files': ['/substitutions'], } -# absolute or relative path to the psa_spec material from this file -# atg_sphinx_spec_dir = '../atg-sphinx-spec' - -# Set up and run the atg-sphinx-spec configuration +# Set up and run the psa-api-tool configuration import os -atg_sphinx_spec_dir = os.environ.get('ATG_SPHINX_SPEC') or atg_sphinx_spec_dir -exec(compile(open(os.path.join(atg_sphinx_spec_dir,'atg-sphinx-conf.py'), +psa_api_tool_path = os.path.normpath(os.path.join(os.path.dirname(__file__), '..', '..', 'tools')) +psa_api_tool_path = os.environ.get('PSA_API_TOOL') or psa_api_tool_path +exec(compile(open(os.path.join(psa_api_tool_path,'psa-api-conf.py'), encoding='utf-8').read(), - 'atg-sphinx-conf.py', 'exec')) + 'psa-api-conf.py', 'exec')) diff --git a/doc/crypto/figure/encoding/aead.pdf b/doc/crypto/figure/encoding/aead.pdf index 44c0845c..92c086e1 100644 Binary files a/doc/crypto/figure/encoding/aead.pdf and b/doc/crypto/figure/encoding/aead.pdf differ diff --git a/doc/crypto/figure/encoding/algorithm.pdf b/doc/crypto/figure/encoding/algorithm.pdf index 72925d0b..c22ddb2d 100644 Binary files a/doc/crypto/figure/encoding/algorithm.pdf and b/doc/crypto/figure/encoding/algorithm.pdf differ diff --git a/doc/crypto/figure/encoding/asymmetric_key.pdf b/doc/crypto/figure/encoding/asymmetric_key.pdf index 3ec7e03a..5381867b 100644 Binary files a/doc/crypto/figure/encoding/asymmetric_key.pdf and b/doc/crypto/figure/encoding/asymmetric_key.pdf differ diff --git a/doc/crypto/figure/encoding/cipher.pdf b/doc/crypto/figure/encoding/cipher.pdf index b1999d90..97420df1 100644 Binary files a/doc/crypto/figure/encoding/cipher.pdf and b/doc/crypto/figure/encoding/cipher.pdf differ diff --git a/doc/crypto/figure/encoding/dh_key.pdf b/doc/crypto/figure/encoding/dh_key.pdf index 4b78e383..6e121e91 100644 Binary files a/doc/crypto/figure/encoding/dh_key.pdf and b/doc/crypto/figure/encoding/dh_key.pdf differ diff --git a/doc/crypto/figure/encoding/ecc_key.pdf b/doc/crypto/figure/encoding/ecc_key.pdf index 5bdfb282..66743c22 100644 Binary files a/doc/crypto/figure/encoding/ecc_key.pdf and b/doc/crypto/figure/encoding/ecc_key.pdf differ diff --git a/doc/crypto/figure/encoding/hash.pdf b/doc/crypto/figure/encoding/hash.pdf index 0bcbf409..347e7daf 100644 Binary files a/doc/crypto/figure/encoding/hash.pdf and b/doc/crypto/figure/encoding/hash.pdf differ diff --git a/doc/crypto/figure/encoding/ka_combined.pdf b/doc/crypto/figure/encoding/ka_combined.pdf index d6f10d87..3f05d72f 100644 Binary files a/doc/crypto/figure/encoding/ka_combined.pdf and b/doc/crypto/figure/encoding/ka_combined.pdf differ diff --git a/doc/crypto/figure/encoding/ka_raw.pdf b/doc/crypto/figure/encoding/ka_raw.pdf index 2c86eb0d..3dd5185e 100644 Binary files a/doc/crypto/figure/encoding/ka_raw.pdf and b/doc/crypto/figure/encoding/ka_raw.pdf differ diff --git a/doc/crypto/figure/encoding/kdf.pdf b/doc/crypto/figure/encoding/kdf.pdf index ea2d9f30..6ce65f59 100644 Binary files a/doc/crypto/figure/encoding/kdf.pdf and b/doc/crypto/figure/encoding/kdf.pdf differ diff --git a/doc/crypto/figure/encoding/kem_encoding.pdf b/doc/crypto/figure/encoding/kem_encoding.pdf index 82434ce5..b700ca56 100644 Binary files a/doc/crypto/figure/encoding/kem_encoding.pdf and b/doc/crypto/figure/encoding/kem_encoding.pdf differ diff --git a/doc/crypto/figure/encoding/key-wrap.pdf b/doc/crypto/figure/encoding/key-wrap.pdf index b708f0c9..2821a1ee 100644 Binary files a/doc/crypto/figure/encoding/key-wrap.pdf and b/doc/crypto/figure/encoding/key-wrap.pdf differ diff --git a/doc/crypto/figure/encoding/key-wrap.svg b/doc/crypto/figure/encoding/key-wrap.svg index 8170d07c..b80bdd43 100644 --- a/doc/crypto/figure/encoding/key-wrap.svg +++ b/doc/crypto/figure/encoding/key-wrap.svg @@ -1,2 +1,2 @@ -07815162122232430310WRAP-TYPE0BS0x0B0 \ No newline at end of file +07815162122232430310WRAP-TYPE0BS0x0B0 \ No newline at end of file diff --git a/doc/crypto/figure/encoding/key_type.pdf b/doc/crypto/figure/encoding/key_type.pdf index 9cdf9ffb..a0d50725 100644 Binary files a/doc/crypto/figure/encoding/key_type.pdf and b/doc/crypto/figure/encoding/key_type.pdf differ diff --git a/doc/crypto/figure/encoding/mac.json b/doc/crypto/figure/encoding/mac.json index 9d024995..c0324253 100644 --- a/doc/crypto/figure/encoding/mac.json +++ b/doc/crypto/figure/encoding/mac.json @@ -11,7 +11,7 @@ ], "config": { "lanes": 1, - "fontfamily": "lato", + "fontfamily": "roboto", "fontsize": 11, "vspace": 52, "hspace": 600 diff --git a/doc/crypto/figure/encoding/mac.pdf b/doc/crypto/figure/encoding/mac.pdf index 28c03bb7..721bf6b6 100644 Binary files a/doc/crypto/figure/encoding/mac.pdf and b/doc/crypto/figure/encoding/mac.pdf differ diff --git a/doc/crypto/figure/encoding/mac.svg b/doc/crypto/figure/encoding/mac.svg index 0b578cdb..4983f317 100644 --- a/doc/crypto/figure/encoding/mac.svg +++ b/doc/crypto/figure/encoding/mac.svg @@ -1,2 +1,2 @@ -078141516212223243031HASH-TYPE or 0MAC-TYPEWLENB10x030 \ No newline at end of file +078141516212223243031HASH-TYPE or 0MAC-TYPEWLENB10x030 \ No newline at end of file diff --git a/doc/crypto/figure/encoding/np_key.pdf b/doc/crypto/figure/encoding/np_key.pdf index 3fd01139..7c3ec8ff 100644 Binary files a/doc/crypto/figure/encoding/np_key.pdf and b/doc/crypto/figure/encoding/np_key.pdf differ diff --git a/doc/crypto/figure/encoding/pake_encoding.pdf b/doc/crypto/figure/encoding/pake_encoding.pdf index 96f94744..214de734 100644 Binary files a/doc/crypto/figure/encoding/pake_encoding.pdf and b/doc/crypto/figure/encoding/pake_encoding.pdf differ diff --git a/doc/crypto/figure/encoding/pke.pdf b/doc/crypto/figure/encoding/pke.pdf index 3a26571f..1a2b2eae 100644 Binary files a/doc/crypto/figure/encoding/pke.pdf and b/doc/crypto/figure/encoding/pke.pdf differ diff --git a/doc/crypto/figure/encoding/raw_key.pdf b/doc/crypto/figure/encoding/raw_key.pdf index c6e94514..12bfdbc8 100644 Binary files a/doc/crypto/figure/encoding/raw_key.pdf and b/doc/crypto/figure/encoding/raw_key.pdf differ diff --git a/doc/crypto/figure/encoding/sign.pdf b/doc/crypto/figure/encoding/sign.pdf index 752da30a..1c34df95 100644 Binary files a/doc/crypto/figure/encoding/sign.pdf and b/doc/crypto/figure/encoding/sign.pdf differ diff --git a/doc/crypto/figure/encoding/slh_dsa_key.pdf b/doc/crypto/figure/encoding/slh_dsa_key.pdf index 9da4f437..4168683c 100644 Binary files a/doc/crypto/figure/encoding/slh_dsa_key.pdf and b/doc/crypto/figure/encoding/slh_dsa_key.pdf differ diff --git a/doc/crypto/figure/encoding/spake2p_key.pdf b/doc/crypto/figure/encoding/spake2p_key.pdf index 84aab337..f200a285 100644 Binary files a/doc/crypto/figure/encoding/spake2p_key.pdf and b/doc/crypto/figure/encoding/spake2p_key.pdf differ diff --git a/doc/crypto/figure/encoding/structured_key.pdf b/doc/crypto/figure/encoding/structured_key.pdf index a27a2c8a..5bf0483a 100644 Binary files a/doc/crypto/figure/encoding/structured_key.pdf and b/doc/crypto/figure/encoding/structured_key.pdf differ diff --git a/doc/crypto/figure/encoding/symmetric_key.pdf b/doc/crypto/figure/encoding/symmetric_key.pdf index abe4e207..31369b87 100644 Binary files a/doc/crypto/figure/encoding/symmetric_key.pdf and b/doc/crypto/figure/encoding/symmetric_key.pdf differ diff --git a/doc/crypto/figure/encoding/wpa3_sae_dh_key.pdf b/doc/crypto/figure/encoding/wpa3_sae_dh_key.pdf index fbfb90f2..2d53f77e 100644 Binary files a/doc/crypto/figure/encoding/wpa3_sae_dh_key.pdf and b/doc/crypto/figure/encoding/wpa3_sae_dh_key.pdf differ diff --git a/doc/crypto/figure/encoding/wpa3_sae_ecc_key.pdf b/doc/crypto/figure/encoding/wpa3_sae_ecc_key.pdf index 00cf9690..f085fc5b 100644 Binary files a/doc/crypto/figure/encoding/wpa3_sae_ecc_key.pdf and b/doc/crypto/figure/encoding/wpa3_sae_ecc_key.pdf differ diff --git a/doc/crypto/figure/encoding/xof.pdf b/doc/crypto/figure/encoding/xof.pdf index 67203579..5d04a892 100644 Binary files a/doc/crypto/figure/encoding/xof.pdf and b/doc/crypto/figure/encoding/xof.pdf differ diff --git a/doc/crypto/figure/multi_part_operation.pdf b/doc/crypto/figure/multi_part_operation.pdf index ae338701..7952baff 100644 Binary files a/doc/crypto/figure/multi_part_operation.pdf and b/doc/crypto/figure/multi_part_operation.pdf differ diff --git a/doc/crypto/figure/multi_part_operation.puml b/doc/crypto/figure/multi_part_operation.puml index c73cf3cc..add60e78 100644 --- a/doc/crypto/figure/multi_part_operation.puml +++ b/doc/crypto/figure/multi_part_operation.puml @@ -2,7 +2,7 @@ ' SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license @startuml -!include atg-spec.pumh +!include psa-spec.pumh skinparam LegendFontSize 12 diff --git a/doc/crypto/figure/multi_part_operation.svg b/doc/crypto/figure/multi_part_operation.svg index c4b63b5f..bb52fcab 100644 --- a/doc/crypto/figure/multi_part_operation.svg +++ b/doc/crypto/figure/multi_part_operation.svg @@ -1 +1 @@ -inactiveactiveerrorOperation object starts asuninitialised memoryInitializeSetupFinishAbortUpdateAbortSetupfailsUpdatefailsFinishfails———Solid lines show successful operation---Dashed lines show error flows………Dotted lines show operation cancellation \ No newline at end of file +inactiveactiveerrorOperation object starts asuninitialised memoryInitializeSetupFinishAbortUpdateAbortSetupfailsUpdatefailsFinishfails———Solid lines show successful operation---Dashed lines show error flows………Dotted lines show operation cancellation \ No newline at end of file diff --git a/doc/crypto/figure/pake/j-pake.pdf b/doc/crypto/figure/pake/j-pake.pdf index c253f31e..b837dd7c 100644 Binary files a/doc/crypto/figure/pake/j-pake.pdf and b/doc/crypto/figure/pake/j-pake.pdf differ diff --git a/doc/crypto/figure/pake/j-pake.puml b/doc/crypto/figure/pake/j-pake.puml index defeff76..cb9e4da7 100644 --- a/doc/crypto/figure/pake/j-pake.puml +++ b/doc/crypto/figure/pake/j-pake.puml @@ -3,7 +3,7 @@ @startuml - !include atg-spec.pumh + !include psa-spec.pumh participant User participant Peer diff --git a/doc/crypto/figure/pake/j-pake.svg b/doc/crypto/figure/pake/j-pake.svg index 504f90f2..39035190 100644 --- a/doc/crypto/figure/pake/j-pake.svg +++ b/doc/crypto/figure/pake/j-pake.svg @@ -1 +1 @@ -UserPeerUserPeerShared information: cipher suite, secrets,UserId, andPeerIdpsa_pake_setup()psa_pake_set_user()psa_pake_set_peer()Generatex1andx2Compute public keysg1andg2Compute ZKP(V1, r1)forg1and(V2, r2)forg2Generatex3andx4Compute public keysg3andg4Compute ZKPs(V3, r3)forg3and(V4, r4)forg4psa_pake_output()forg1, V1, r1, g2, V2, andr2(g1, V1, r1, g2, V2, r2)(g3, V3, r3, g4, V4, r4)psa_pake_input()forg3, V3, r3, g4, V4, andr4Verify ZKPs and computeAand ZKP(V5, r5)forx2*sVerify ZKPs and computeBand ZKP(V6, r6)forx4*spsa_pake_output()forA, V5, andr5(A, V5, r5)(B, V6, r6)psa_pake_input()forB, V6, andr6Verify ZKP and computeKaVerify ZKP and computeKbIf both sides used the same secrets, thenKa=Kbpsa_pake_get_shared_key()to extractKa \ No newline at end of file +UserPeerUserPeerShared information: cipher suite, secrets,UserId, andPeerIdpsa_pake_setup()psa_pake_set_user()psa_pake_set_peer()Generatex1andx2Compute public keysg1andg2Compute ZKP(V1, r1)forg1and(V2, r2)forg2Generatex3andx4Compute public keysg3andg4Compute ZKPs(V3, r3)forg3and(V4, r4)forg4psa_pake_output()forg1, V1, r1, g2, V2, andr2(g1, V1, r1, g2, V2, r2)(g3, V3, r3, g4, V4, r4)psa_pake_input()forg3, V3, r3, g4, V4, andr4Verify ZKPs and computeAand ZKP(V5, r5)forx2*sVerify ZKPs and computeBand ZKP(V6, r6)forx4*spsa_pake_output()forA, V5, andr5(A, V5, r5)(B, V6, r6)psa_pake_input()forB, V6, andr6Verify ZKP and computeKaVerify ZKP and computeKbIf both sides used the same secrets, thenKa=Kbpsa_pake_get_shared_key()to extractKa \ No newline at end of file diff --git a/doc/crypto/figure/pake/pake_primitive.pdf b/doc/crypto/figure/pake/pake_primitive.pdf index b0be8d75..a46ad088 100644 Binary files a/doc/crypto/figure/pake/pake_primitive.pdf and b/doc/crypto/figure/pake/pake_primitive.pdf differ diff --git a/doc/crypto/figure/pake/spake2plus-reg.pdf b/doc/crypto/figure/pake/spake2plus-reg.pdf index eba88a3b..7a69320a 100644 Binary files a/doc/crypto/figure/pake/spake2plus-reg.pdf and b/doc/crypto/figure/pake/spake2plus-reg.pdf differ diff --git a/doc/crypto/figure/pake/spake2plus-reg.puml b/doc/crypto/figure/pake/spake2plus-reg.puml index f642280a..22e42ede 100644 --- a/doc/crypto/figure/pake/spake2plus-reg.puml +++ b/doc/crypto/figure/pake/spake2plus-reg.puml @@ -3,7 +3,7 @@ @startuml - !include atg-spec.pumh + !include psa-spec.pumh participant "Prover //(Client role)//" as Prover participant "Verifier //(Server role)//" as Verifier diff --git a/doc/crypto/figure/pake/spake2plus-reg.svg b/doc/crypto/figure/pake/spake2plus-reg.svg index 9793195b..c4390d03 100644 --- a/doc/crypto/figure/pake/spake2plus-reg.svg +++ b/doc/crypto/figure/pake/spake2plus-reg.svg @@ -1 +1 @@ -Prover //(Client role)//Verifier //(Server role)//Prover(Client role)Verifier(Server role)Initial information : cipher suite,PBKDF-params,passwordpsa_key_derivation_setup(PBKDF)psa_key_derivation_input_key(password)psa_key_derivation_input_xxx()forPBKDF-paramspsa_key_derivation_output_key(SPAKE2P_KEY_PAIR)Compute key pair (w0,w1)alt[Independent registration]psa_key_derivation_setup(PBKDF)psa_key_derivation_input_key(password)psa_key_derivation_input_xxx()forPBKDF-paramspsa_key_derivation_output_key(SPAKE2P_KEY_PAIR)Compute key pair (w0,w1)[Connected registration]psa_export_public_key()ComputeLand outputw0||LRegistration record (w0||L)psa_import_key(SPAKE2P_PUBLIC_KEY)fromw0||LImport public key (w0,L)Use key pair for authentication flowUse key for authentication flow \ No newline at end of file +Prover //(Client role)//Verifier //(Server role)//Prover(Client role)Verifier(Server role)Initial information : cipher suite,PBKDF-params,passwordpsa_key_derivation_setup(PBKDF)psa_key_derivation_input_key(password)psa_key_derivation_input_xxx()forPBKDF-paramspsa_key_derivation_output_key(SPAKE2P_KEY_PAIR)Compute key pair (w0,w1)alt[Independent registration]psa_key_derivation_setup(PBKDF)psa_key_derivation_input_key(password)psa_key_derivation_input_xxx()forPBKDF-paramspsa_key_derivation_output_key(SPAKE2P_KEY_PAIR)Compute key pair (w0,w1)[Connected registration]psa_export_public_key()ComputeLand outputw0||LRegistration record (w0||L)psa_import_key(SPAKE2P_PUBLIC_KEY)fromw0||LImport public key (w0,L)Use key pair for authentication flowUse key for authentication flow \ No newline at end of file diff --git a/doc/crypto/figure/pake/spake2plus.pdf b/doc/crypto/figure/pake/spake2plus.pdf index 2089c016..bc9376bc 100644 Binary files a/doc/crypto/figure/pake/spake2plus.pdf and b/doc/crypto/figure/pake/spake2plus.pdf differ diff --git a/doc/crypto/figure/pake/spake2plus.puml b/doc/crypto/figure/pake/spake2plus.puml index cc91b8b0..08d95cbb 100644 --- a/doc/crypto/figure/pake/spake2plus.puml +++ b/doc/crypto/figure/pake/spake2plus.puml @@ -3,7 +3,7 @@ @startuml - !include atg-spec.pumh + !include psa-spec.pumh participant "Prover //(Client role)//" as Prover participant "Verifier //(Server role)//" as Verifier diff --git a/doc/crypto/figure/pake/spake2plus.svg b/doc/crypto/figure/pake/spake2plus.svg index ecf05127..6808a929 100644 --- a/doc/crypto/figure/pake/spake2plus.svg +++ b/doc/crypto/figure/pake/spake2plus.svg @@ -1 +1 @@ -Prover //(Client role)//Verifier //(Server role)//Prover(Client role)Verifier(Server role)Shared information : cipher suite,ProverId,VerifierId, andContextRegistration record (w0,L) derived from passwordProver 'key pair' (w0,w1) derived from passwordpsa_pake_setup()with key (w0,w1)psa_pake_set_role(PSA_PAKE_ROLE_CLIENT)psa_pake_set_user(ProverId)psa_pake_set_peer(VerifierId)psa_pake_set_context(Context)psa_pake_output()forshareP=XGenerate key shareX(shareP)psa_pake_setup()with key (w0,L) or key (w0,w1)psa_pake_set_role(PSA_PAKE_ROLE_SERVER)psa_pake_set_user(VerifierId)psa_pake_set_peer(ProverId)psa_pake_set_context(Context)psa_pake_input()forsharePValidatesharePpsa_pake_output()forshareV=YGenerate key shareYpsa_pake_output()forconfirmVComputeK_shared,confirmP'andconfirmV(shareV,confirmV)psa_pake_input()forshareVValidateshareVpsa_pake_input()forconfirmVComputeK_shared,    confirmPandconfirmV'VerifyconfirmV'=confirmVpsa_pake_output()forconfirmP(confirmP)psa_pake_get_shared_key()to extractK_sharedpsa_pake_input()forconfirmPVerifyconfirmP'=confirmPpsa_pake_get_shared_key()to extractK_shared \ No newline at end of file +Prover //(Client role)//Verifier //(Server role)//Prover(Client role)Verifier(Server role)Shared information : cipher suite,ProverId,VerifierId, andContextRegistration record (w0,L) derived from passwordProver 'key pair' (w0,w1) derived from passwordpsa_pake_setup()with key (w0,w1)psa_pake_set_role(PSA_PAKE_ROLE_CLIENT)psa_pake_set_user(ProverId)psa_pake_set_peer(VerifierId)psa_pake_set_context(Context)psa_pake_output()forshareP=XGenerate key shareX(shareP)psa_pake_setup()with key (w0,L) or key (w0,w1)psa_pake_set_role(PSA_PAKE_ROLE_SERVER)psa_pake_set_user(VerifierId)psa_pake_set_peer(ProverId)psa_pake_set_context(Context)psa_pake_input()forsharePValidatesharePpsa_pake_output()forshareV=YGenerate key shareYpsa_pake_output()forconfirmVComputeK_shared,confirmP'andconfirmV(shareV,confirmV)psa_pake_input()forshareVValidateshareVpsa_pake_input()forconfirmVComputeK_shared,    confirmPandconfirmV'VerifyconfirmV'=confirmVpsa_pake_output()forconfirmP(confirmP)psa_pake_get_shared_key()to extractK_sharedpsa_pake_input()forconfirmPVerifyconfirmP'=confirmPpsa_pake_get_shared_key()to extractK_shared \ No newline at end of file diff --git a/doc/crypto/figure/pake/wpa3-sae-pt.pdf b/doc/crypto/figure/pake/wpa3-sae-pt.pdf index fc41d3a9..4af3540d 100644 Binary files a/doc/crypto/figure/pake/wpa3-sae-pt.pdf and b/doc/crypto/figure/pake/wpa3-sae-pt.pdf differ diff --git a/doc/crypto/figure/pake/wpa3-sae-pt.puml b/doc/crypto/figure/pake/wpa3-sae-pt.puml index bc4b0ec4..17afd73c 100644 --- a/doc/crypto/figure/pake/wpa3-sae-pt.puml +++ b/doc/crypto/figure/pake/wpa3-sae-pt.puml @@ -3,7 +3,7 @@ @startuml - !include atg-spec.pumh + !include psa-spec.pumh participant "station (STA)" as Participant diff --git a/doc/crypto/figure/pake/wpa3-sae-pt.svg b/doc/crypto/figure/pake/wpa3-sae-pt.svg index 7287cd9b..5f575e1e 100644 --- a/doc/crypto/figure/pake/wpa3-sae-pt.svg +++ b/doc/crypto/figure/pake/wpa3-sae-pt.svg @@ -1 +1 @@ -station (STA)station (STA)Initial information : cipher suite,SSID,password[,password-identifier]alt[Hash-to-element generation of password element]psa_key_derivation_setup(WPA3_SAE_H2E)psa_key_derivation_input_bytes(SALT = SSID)psa_key_derivation_input_key(PASSWORD = password)optpsa_key_derivation_input_bytes(INFO = password-identifier)psa_key_derivation_output_key(WPA3_SAE_XX)Compute password tokenPTUsePTfor authentication flow[Generation of the password element by looping]Usepasswordfor authentication flow \ No newline at end of file +station (STA)station (STA)Initial information : cipher suite,SSID,password[,password-identifier]alt[Hash-to-element generation of password element]psa_key_derivation_setup(WPA3_SAE_H2E)psa_key_derivation_input_bytes(SALT = SSID)psa_key_derivation_input_key(PASSWORD = password)optpsa_key_derivation_input_bytes(INFO = password-identifier)psa_key_derivation_output_key(WPA3_SAE_XX)Compute password tokenPTUsePTfor authentication flow[Generation of the password element by looping]Usepasswordfor authentication flow \ No newline at end of file diff --git a/doc/crypto/figure/pake/wpa3-sae.pdf b/doc/crypto/figure/pake/wpa3-sae.pdf index a8f84edf..1fb66565 100644 Binary files a/doc/crypto/figure/pake/wpa3-sae.pdf and b/doc/crypto/figure/pake/wpa3-sae.pdf differ diff --git a/doc/crypto/figure/pake/wpa3-sae.puml b/doc/crypto/figure/pake/wpa3-sae.puml index bb99bed6..0c0f3e01 100644 --- a/doc/crypto/figure/pake/wpa3-sae.puml +++ b/doc/crypto/figure/pake/wpa3-sae.puml @@ -3,7 +3,7 @@ @startuml - !include atg-spec.pumh + !include psa-spec.pumh participant "STA-A" as STAA participant "STA-B" as STAB diff --git a/doc/crypto/figure/pake/wpa3-sae.svg b/doc/crypto/figure/pake/wpa3-sae.svg index f10f160b..e8eeae61 100644 --- a/doc/crypto/figure/pake/wpa3-sae.svg +++ b/doc/crypto/figure/pake/wpa3-sae.svg @@ -1 +1 @@ -STA-ASTA-BSTA-ASTA-BShared information: cipher suite,STA-A-MAC,STA-B-MACIf generating PWE by looping:passwordIf generating PWE by hash-to-element:PTpsa_pake_setup()psa_pake_set_user(STA-A-MAC)psa_pake_set_peer(STA-B-MAC)Provide eitherpasswordorPTtopsa_pake_setup()dependingon PWE generation methodpsa_pake_output()forcommit-scalar||COMMIT-ELEMENTGeneraterand,mask; computecommit-scalar,COMMIT-ELEMENTSAE Commitframe(commit-scalar, COMMIT-ELEMENT)SAE Commitframe(peer-commit-scalar, PEER-COMMIT-ELEMENT)psa_pake_input()forpeer-commit-scalar||PEER-COMMIT-ELEMENTValidate inputs; computekpsa_pake_input()forsaltComputeSAE-KCK,PMKloop[UntilSAE Confirmframe is successfully delivered to STA-B]psa_pake_input()forsend-confirmcounterpsa_pake_output()forsend-confirm||confirmComputeconfirmSAE Confirmframe(send-confirm, confirm)SAE Confirmframe(peer-send-confirm, peer-confirm)psa_pake_input()forpeer-send-confirm||peer-confirmCompute and validatepeer-verify=peer-confirmoptpsa_pake_output()forPMKIDpsa_pake_get_shared_key()to extractPMK \ No newline at end of file +STA-ASTA-BSTA-ASTA-BShared information: cipher suite,STA-A-MAC,STA-B-MACIf generating PWE by looping:passwordIf generating PWE by hash-to-element:PTpsa_pake_setup()psa_pake_set_user(STA-A-MAC)psa_pake_set_peer(STA-B-MAC)Provide eitherpasswordorPTtopsa_pake_setup()dependingon PWE generation methodpsa_pake_output()forcommit-scalar||COMMIT-ELEMENTGeneraterand,mask; computecommit-scalar,COMMIT-ELEMENTSAE Commitframe(commit-scalar, COMMIT-ELEMENT)SAE Commitframe(peer-commit-scalar, PEER-COMMIT-ELEMENT)psa_pake_input()forpeer-commit-scalar||PEER-COMMIT-ELEMENTValidate inputs; computekpsa_pake_input()forsaltComputeSAE-KCK,PMKloop[UntilSAE Confirmframe is successfully delivered to STA-B]psa_pake_input()forsend-confirmcounterpsa_pake_output()forsend-confirm||confirmComputeconfirmSAE Confirmframe(send-confirm, confirm)SAE Confirmframe(peer-send-confirm, peer-confirm)psa_pake_input()forpeer-send-confirm||peer-confirmCompute and validatepeer-verify=peer-confirmoptpsa_pake_output()forPMKIDpsa_pake_get_shared_key()to extractPMK \ No newline at end of file diff --git a/doc/crypto/figure/sra/dfd_caller_isolation.pdf b/doc/crypto/figure/sra/dfd_caller_isolation.pdf index 0b335213..bef78359 100644 Binary files a/doc/crypto/figure/sra/dfd_caller_isolation.pdf and b/doc/crypto/figure/sra/dfd_caller_isolation.pdf differ diff --git a/doc/crypto/figure/sra/dfd_caller_isolation.puml b/doc/crypto/figure/sra/dfd_caller_isolation.puml index 08ca3c24..0328b364 100644 --- a/doc/crypto/figure/sra/dfd_caller_isolation.puml +++ b/doc/crypto/figure/sra/dfd_caller_isolation.puml @@ -2,8 +2,8 @@ ' SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license @startuml -!include atg-spec.pumh -!include atg-dataflow.pumh +!include psa-spec.pumh +!include psa-dataflow.pumh dfd_agent "External system" as ext dfd_agent "External system" as ext2 diff --git a/doc/crypto/figure/sra/dfd_caller_isolation.svg b/doc/crypto/figure/sra/dfd_caller_isolation.svg index e2a58a2c..ce0ee9d7 100644 --- a/doc/crypto/figure/sra/dfd_caller_isolation.svg +++ b/doc/crypto/figure/sra/dfd_caller_isolation.svg @@ -1 +1 @@ -«System boundary»«Application boundary»«Application boundary»«Cryptoprocessor boundary»NVMApplicationOther applicationCryptoprocessorKey StoreExternal systemExternal systemciphertextciphertextciphertextciphertextCrypto APIcallresponsestore keyload keyCrypto APIcallresponse \ No newline at end of file +«System boundary»«Application boundary»«Application boundary»«Cryptoprocessor boundary»NVMApplicationOther applicationCryptoprocessorKey StoreExternal systemExternal systemciphertextciphertextciphertextciphertextCrypto APIcallresponsestore keyload keyCrypto APIcallresponse \ No newline at end of file diff --git a/doc/crypto/figure/sra/dfd_crypto_isolation.pdf b/doc/crypto/figure/sra/dfd_crypto_isolation.pdf index 431934e7..ad25012e 100644 Binary files a/doc/crypto/figure/sra/dfd_crypto_isolation.pdf and b/doc/crypto/figure/sra/dfd_crypto_isolation.pdf differ diff --git a/doc/crypto/figure/sra/dfd_crypto_isolation.puml b/doc/crypto/figure/sra/dfd_crypto_isolation.puml index 94da4da2..0e804843 100644 --- a/doc/crypto/figure/sra/dfd_crypto_isolation.puml +++ b/doc/crypto/figure/sra/dfd_crypto_isolation.puml @@ -2,8 +2,8 @@ ' SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license @startuml -!include atg-spec.pumh -!include atg-dataflow.pumh +!include psa-spec.pumh +!include psa-dataflow.pumh dfd_agent "External system" as ext dfd_tb("System boundary") { diff --git a/doc/crypto/figure/sra/dfd_crypto_isolation.svg b/doc/crypto/figure/sra/dfd_crypto_isolation.svg index 41cdc813..9b2c5763 100644 --- a/doc/crypto/figure/sra/dfd_crypto_isolation.svg +++ b/doc/crypto/figure/sra/dfd_crypto_isolation.svg @@ -1 +1 @@ -«System boundary»«Cryptoprocessor boundary»ApplicationNVMCryptoprocessorKey StoreExternal systemciphertextciphertextCrypto APIcallresponsestore keyload key \ No newline at end of file +«System boundary»«Cryptoprocessor boundary»ApplicationNVMCryptoprocessorKey StoreExternal systemciphertextciphertextCrypto APIcallresponsestore keyload key \ No newline at end of file diff --git a/doc/crypto/figure/sra/dfd_no_isolation.pdf b/doc/crypto/figure/sra/dfd_no_isolation.pdf index 85b42b31..40fe0f63 100644 Binary files a/doc/crypto/figure/sra/dfd_no_isolation.pdf and b/doc/crypto/figure/sra/dfd_no_isolation.pdf differ diff --git a/doc/crypto/figure/sra/dfd_no_isolation.puml b/doc/crypto/figure/sra/dfd_no_isolation.puml index ed437af9..a80ca5df 100644 --- a/doc/crypto/figure/sra/dfd_no_isolation.puml +++ b/doc/crypto/figure/sra/dfd_no_isolation.puml @@ -2,8 +2,8 @@ ' SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license @startuml -!include atg-spec.pumh -!include atg-dataflow.pumh +!include psa-spec.pumh +!include psa-dataflow.pumh dfd_agent "External system" as ext dfd_tb("System boundary") { diff --git a/doc/crypto/figure/sra/dfd_no_isolation.svg b/doc/crypto/figure/sra/dfd_no_isolation.svg index 8133e751..efa5b5c1 100644 --- a/doc/crypto/figure/sra/dfd_no_isolation.svg +++ b/doc/crypto/figure/sra/dfd_no_isolation.svg @@ -1 +1 @@ -«System boundary»ApplicationCryptoprocessorKey StoreNVMExternal systemciphertextCrypto API callresponsestore keyload keyciphertext \ No newline at end of file +«System boundary»ApplicationCryptoprocessorKey StoreNVMExternal systemciphertextCrypto API callresponsestore keyload keyciphertext \ No newline at end of file diff --git a/doc/crypto/figure/sra/system-entities.pdf b/doc/crypto/figure/sra/system-entities.pdf index ff320def..319056c0 100644 Binary files a/doc/crypto/figure/sra/system-entities.pdf and b/doc/crypto/figure/sra/system-entities.pdf differ diff --git a/doc/crypto/figure/sra/system-entities.puml b/doc/crypto/figure/sra/system-entities.puml index 061c3b3b..2e0a66f7 100644 --- a/doc/crypto/figure/sra/system-entities.puml +++ b/doc/crypto/figure/sra/system-entities.puml @@ -2,7 +2,7 @@ ' SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license @startuml -!include atg-spec.pumh +!include psa-spec.pumh skinparam defaultTextAlignment center diff --git a/doc/crypto/figure/sra/system-entities.svg b/doc/crypto/figure/sra/system-entities.svg index 8fe9190d..89f4f4ae 100644 --- a/doc/crypto/figure/sra/system-entities.svg +++ b/doc/crypto/figure/sra/system-entities.svg @@ -1 +1 @@ -Crypto APIApplicationCryptoprocessorcall \ No newline at end of file +Crypto APIApplicationCryptoprocessorcall \ No newline at end of file diff --git a/doc/crypto/index.rst b/doc/crypto/index.rst index 05a13b3d..5e84429c 100644 --- a/doc/crypto/index.rst +++ b/doc/crypto/index.rst @@ -3,17 +3,9 @@ .. title:: - .. abstract:: - - This document is part of the PSA Certified API specifications. It defines interfaces to provide cryptographic operations and key storage services. - -.. front-matter:: - - about/about - .. maintoc:: - overview/intro + about/about overview/goals overview/functionality overview/sample-arch diff --git a/doc/crypto/overview/conventions.rst b/doc/crypto/overview/conventions.rst index a286a243..59786c96 100644 --- a/doc/crypto/overview/conventions.rst +++ b/doc/crypto/overview/conventions.rst @@ -17,7 +17,7 @@ The header file for the |API| has the name :file:`psa/crypto.h`. All of the API Implementations must provide their own version of the :file:`psa/crypto.h` header file. Implementations can provide a subset of the API defined in this specification and a subset of the available algorithms. :secref:`appendix-example-header` provides an incomplete, example header file which includes all of the API elements. See also :secref:`implementation-considerations`. -The |API| uses the status code definitions that are shared with the other PSA Certified APIs. :cite-title:`PSA-STAT` defines these status codes in the :file:`psa/error.h` header file. Applications are not required to explicitly include the :file:`psa/error.h` header file when using these status codes with the |API|. See :secref:`status-codes`. +The |API| uses the status code definitions that are shared with the other PSA Certified APIs. :cite-title:`PSA STAT` defines these status codes in the :file:`psa/error.h` header file. Applications are not required to explicitly include the :file:`psa/error.h` header file when using these status codes with the |API|. See :secref:`status-codes`. .. _api-conventions: diff --git a/doc/crypto/overview/intro.rst b/doc/crypto/overview/intro.rst deleted file mode 100644 index c5da96ad..00000000 --- a/doc/crypto/overview/intro.rst +++ /dev/null @@ -1,31 +0,0 @@ -.. SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited and/or its affiliates -.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license - -Introduction -============ - -About Platform Security Architecture ------------------------------------- - -This document is one of a set of resources provided by Arm that can help organizations develop products that meet the security requirements of GlobalPlatform's PSA Certified evaluation scheme on Arm-based platforms. The PSA Certified scheme provides a framework and methodology that helps silicon manufacturers, system software providers and OEMs to develop more secure products. Arm resources that support PSA Certified range from threat models, standard architectures that simplify development and increase portability, and open-source partnerships that provide ready-to-use software. You can read more about PSA Certified here at :url:`www.psacertified.org` and find more Arm resources here at :url:`developer.arm.com/platform-security-resources` and :url:`www.trustedfirmware.org`. - -About the |API| ---------------- - -The interface described in this document is a PSA Certified API, that provides a portable programming interface to cryptographic operations, and key storage functionality, on a wide range of hardware. - -The interface is user-friendly, while still providing access to the low-level primitives used in modern cryptography. It does not require that the user has access to the key material. Instead, it uses opaque key identifiers. - -You can find additional resources relating to the |API| here at :url:`arm-software.github.io/psa-api/crypto`, and find other PSA Certified APIs here at :url:`arm-software.github.io/psa-api`. - -This document includes: - -* A rationale for the design. See :secref:`design-goals`. -* A high-level overview of the functionality provided by the interface. See :secref:`functionality-overview`. -* A description of typical architectures of implementations for this specification. See :secref:`architectures`. -* General considerations for implementers of this specification, and for applications that use the interface defined in this specification. See :secref:`implementation-considerations` and :secref:`usage-considerations`. -* A detailed definition of the API. See :secref:`library-management`, :secref:`key-management`, and :secref:`crypto-operations`. - -In future, companion documents will define *profiles* for this specification. A profile is -a minimum mandatory subset of the interface that a compliant implementation must -provide. diff --git a/doc/crypto/overview/sample-arch.rst b/doc/crypto/overview/sample-arch.rst index 94e6721e..f4a77142 100644 --- a/doc/crypto/overview/sample-arch.rst +++ b/doc/crypto/overview/sample-arch.rst @@ -18,8 +18,8 @@ application code can access all the system memory, including the memory used by the cryptographic services described in this specification. Thus, the architecture provides :term:`no isolation`. -This architecture does not conform to the Arm *Platform Security Architecture -Security Model*. However, it is useful for providing cryptographic services +This architecture does not conform to the :cite-title:`PSM`. +However, it is useful for providing cryptographic services that use the same interface, even on devices that cannot support any security boundary. So, while this architecture is not the primary design goal of the API defined in the present specification, it is supported. diff --git a/doc/crypto/pyproject.toml b/doc/crypto/pyproject.toml new file mode 100644 index 00000000..52de3a0e --- /dev/null +++ b/doc/crypto/pyproject.toml @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: Copyright 2026 Arm Limited and/or its affiliates +# SPDX-License-Identifier: Apache-2.0 + +[tool.esbonio] diff --git a/doc/fwu/README.md b/doc/fwu/README.md index a3e9a142..4f3756bf 100644 --- a/doc/fwu/README.md +++ b/doc/fwu/README.md @@ -9,7 +9,8 @@ The Firmware Update API specification source files are organized as follows: Folder | Content -- | -- -Current directory | Configuration and front-matter +Current directory | Configuration and table of contents +`about` | Front matter `overview` | Informative chapters 1-4 `api` | API reference chapter 5 `appendix` | Appendix chapters diff --git a/doc/fwu/about.rst b/doc/fwu/about.rst deleted file mode 100644 index 72e99ead..00000000 --- a/doc/fwu/about.rst +++ /dev/null @@ -1,33 +0,0 @@ -.. SPDX-FileCopyrightText: Copyright 2020-2023 Arm Limited and/or its affiliates -.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license - -.. include:: releases - -.. release-info:: - :extend: - - For a detailed list of changes, see :secref:`change-history`. - -.. include:: references - -.. include:: terms - -.. references:: - - This document refers to the following documents. - - .. reference-table:: Documents referenced by this document - :sorted: - -.. potential-for-change:: - - The contents of this specification are stable for version |docversion|. - - The following may change in updates to the version |docversion| specification: - - * Small optional feature additions. - * Clarifications. - - Significant additions, or any changes that affect the compatibility of the interfaces defined in this specification will only be included in a new major or minor version of the specification. - -.. about:: diff --git a/doc/fwu/about/about.rst b/doc/fwu/about/about.rst new file mode 100644 index 00000000..28271cda --- /dev/null +++ b/doc/fwu/about/about.rst @@ -0,0 +1,12 @@ +.. SPDX-FileCopyrightText: Copyright 2020-2023, 2026 Arm Limited and/or its affiliates +.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +.. include:: intro + +.. include:: releases + +.. include:: references + +.. include:: terms + +.. about:: diff --git a/doc/fwu/about/intro b/doc/fwu/about/intro new file mode 100644 index 00000000..6988753c --- /dev/null +++ b/doc/fwu/about/intro @@ -0,0 +1,22 @@ +.. SPDX-FileCopyrightText: Copyright 2020-2026 Arm Limited and/or its affiliates +.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +.. introduction:: + + This document is one of a set of resources that can help organizations develop products that meet the security requirements of GlobalPlatform's PSA Certified evaluation scheme. The PSA Certified scheme provides a framework and methodology that helps silicon manufacturers, system software providers and OEMs to develop more secure products. You can read more about PSA Certified here at :url:`www.psacertified.org`. + + .. rubric:: About the |API| + + The interface described in this document is a PSA Certified API, that provides a portable programming interface to firmware update and installation operations on a wide range of hardware. + + The interface enables the software and systems that manage and deliver a firmware update to a device, to be developed independently from the hardware-specific mechanisms required to apply the update to the device. Reusing the deployment and delivery system for firmware updates reduces the complexity of providing firmware updates across a diverse set of managed devices. + + You can find additional resources relating to the |API| here at :url:`arm-software.github.io/psa-api/fwu`, and find other PSA Certified APIs here at :url:`arm-software.github.io/psa-api`. + +.. audience:: + + This document is intended primarily for the use of developers of: + + * Firmware update services and security frameworks that implement the |API|. + * Bootloaders that provide secure firmware update services. + * Firmware update client applications the use the |API| to access device-specific update functionality. diff --git a/doc/fwu/references b/doc/fwu/about/references similarity index 67% rename from doc/fwu/references rename to doc/fwu/about/references index 2c6c6799..fba6e473 100644 --- a/doc/fwu/references +++ b/doc/fwu/about/references @@ -1,102 +1,107 @@ -.. SPDX-FileCopyrightText: Copyright 2020-2023 Arm Limited and/or its affiliates +.. SPDX-FileCopyrightText: Copyright 2020-2023, 2026 Arm Limited and/or its affiliates .. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license -.. reference:: PSA-STAT - :title: PSA Certified Status code API - :doc_no: ARM IHI 0097 - :url: arm-software.github.io/psa-api/status-code - -.. reference:: PSA-FFM - :title: Arm® Platform Security Architecture Firmware Framework - :doc_no: ARM DEN 0063 - :url: developer.arm.com/documentation/den0063 +.. reference:: PSA STAT + :title: PSA Certified Status code API + :kind: normative + :doc_id: ARM IHI 0097 + :url: arm-software.github.io/psa-api/status-code .. reference:: PSM :title: Platform Security Model - :doc_no: ARM DEN 0128 + :kind: informative + :doc_id: ARM DEN 0128 :url: developer.arm.com/documentation/den0128 .. reference:: PSA-CERT :title: PSA Certified™ Level 2 Lightweight Protection Profile - :doc_no: JSA DEN 002 + :kind: informative + :doc_id: JSA DEN 002 :url: psacertified.org/development-resources/certification-resources/#leveltwo .. reference:: IR8259 :author: NIST - :doc_no: IR 8259 + :doc_id: IR 8259 :title: Foundational Cybersecurity Activities for IoT Device Manufacturers + :kind: informative :publication: May 2020 :url: doi.org/10.6028/NIST.IR.8259 .. reference:: EN303645 :title: Cyber Security for Consumer Internet of Things: Baseline Requirements + :kind: informative :author: ETSI - :doc_no: EN 303 645 + :doc_id: EN 303 645 :publication: June 2020 :url: www.etsi.org/standards/get-standards#search=303%20645 .. reference:: LWM2M :title: Lightweight M2M + :kind: informative :author: OMA - :doc_no: LwM2M v1.2 + :doc_id: LwM2M v1.2 :publication: November 2020 :url: openmobilealliance.org/release/LightweightM2M .. reference:: UEFI :title: Unified Extensible Firmware Interface (UEFI) Specification - :doc_no: UEFI v2.10 + :kind: informative + :doc_id: UEFI v2.10 :author: UEFI Forum, Inc. :publication: August 2022 :url: uefi.org/specifications -.. reference:: RFC4122 - :author: IETF - :title: A Universally Unique IDentifier (UUID) URN Namespace - :url: tools.ietf.org/html/rfc4122 - -.. reference:: RFC8240 +.. reference:: RFC 8240 :title: Report from the Internet of Things Software Update (IoTSU) Workshop 2016 + :kind: informative :author: IAB :publication: September 2017 :url: tools.ietf.org/html/rfc8240 -.. reference:: RFC9019 +.. reference:: RFC 9019 :title: A Firmware Update Architecture for Internet of Things + :kind: informative :author: IETF :publication: April 2021 :url: tools.ietf.org/html/rfc9019 -.. reference:: RFC9124 +.. reference:: RFC 9124 :title: A Manifest Information Model for Firmware Updates in Internet of Things (IoT) Devices + :kind: informative :author: IETF :publication: January 2022 :url: tools.ietf.org/html/rfc9124 .. reference:: SUIT-MFST :title: A Concise Binary Object Representation (CBOR)-based Serialization Format for the Software Updates for Internet of Things (SUIT) Manifest + :kind: informative :author: IETF, (draft) :publication: February 2023 :url: datatracker.ietf.org/doc/draft-ietf-suit-manifest .. reference:: SUIT-ENC :title: Encrypted Payloads in SUIT Manifests + :kind: informative :author: IETF, (draft) :publication: April 2023 :url: datatracker.ietf.org/doc/draft-ietf-suit-firmware-encryption .. reference:: C99 - :title: ISO/IEC 9899:1999 --- Programming Languages --- C - :author: ISO/IEC - :publication: December 1999 - :url: www.iso.org/standard/29237.html + :title: Programming Languages --- C + :kind: informative + :doc_id: ISO/IEC 9899:1999 + :publication: December 1999 + :url: www.iso.org/standard/29237.html .. reference:: EBBR :author: Arm Limited and Contributors :title: Embedded Base Boot Requirements (EBBR) Specification + :kind: informative :url: arm-software.github.io/ebbr .. reference:: SP800-30 - :title: NIST Special Publication 800-30 Revision 1: Guide for Conducting Risk Assessments - :author: NIST - :publication: September 2012 - :url: doi.org/10.6028/NIST.SP.800-30r1 + :title: Special Publication 800-30 Revision 1: Guide for Conducting Risk Assessments + :kind: informative + :author: NIST + :publication: September 2012 + :url: doi.org/10.6028/NIST.SP.800-30r1 diff --git a/doc/fwu/releases b/doc/fwu/about/releases similarity index 88% rename from doc/fwu/releases rename to doc/fwu/about/releases index 9aaa973f..733f6e1a 100644 --- a/doc/fwu/releases +++ b/doc/fwu/about/releases @@ -28,3 +28,9 @@ :confidentiality: Non-confidential GlobalPlatform governance of PSA Certified evaluation scheme. + + +.. release-info:: + :extend: + + For a detailed list of changes, see :secref:`change-history`. diff --git a/doc/fwu/terms b/doc/fwu/about/terms similarity index 100% rename from doc/fwu/terms rename to doc/fwu/about/terms diff --git a/doc/fwu/api/api.rst b/doc/fwu/api/api.rst index 4d3d4ef8..c5f634ad 100644 --- a/doc/fwu/api/api.rst +++ b/doc/fwu/api/api.rst @@ -133,10 +133,7 @@ The header file for the |API| has the name :file:`psa/update.h`. All of the inte Implementations must provide their own version of the :file:`psa/update.h` header file. :secref:`appendix-example-header` provides an incomplete, example header file which includes all of the |API| elements. -This |API| uses some of the common status codes that are defined by :cite-title:`PSA-STAT` as part of the :file:`psa/error.h` header file. Applications are not required to explicitly include the :file:`psa/error.h` header file when using these status codes with the |API|. See :secref:`status-codes`. - -.. note:: - The common error codes in :file:`psa/error.h` were previously defined in :cite-title:`PSA-FFM`. +This |API| uses some of the common status codes that are defined by :cite-title:`PSA STAT` as part of the :file:`psa/error.h` header file. Applications are not required to explicitly include the :file:`psa/error.h` header file when using these status codes with the |API|. See :secref:`status-codes`. .. _required_functions: @@ -200,7 +197,7 @@ The |API| uses the status code definitions that are shared with the other PSA Ce Common status codes ^^^^^^^^^^^^^^^^^^^ -The following elements are defined in :file:`psa/error.h` from :cite:`PSA-STAT` (previously defined in :cite:`PSA-FFM`): +The following elements are defined in :file:`psa/error.h` from :cite:`PSA STAT`: .. code-block:: xref diff --git a/doc/fwu/appendix/change-history.rst b/doc/fwu/appendix/change-history.rst index 0b8c7691..2720eeba 100644 --- a/doc/fwu/appendix/change-history.rst +++ b/doc/fwu/appendix/change-history.rst @@ -6,6 +6,15 @@ Document change history ======================= +Changes in the draft GlobalPlatform publication revision +-------------------------------------------------------- + +.. rubric:: General changes + +* Migrated the document to the 2026 PSA Certified API template. + + This changes the document front matter structure and publication styling, without changing the API. + Changes between version *1.0.0* and *1.0.1* ------------------------------------------- diff --git a/doc/fwu/conf.py b/doc/fwu/conf.py index 3dea5982..9c83f70a 100644 --- a/doc/fwu/conf.py +++ b/doc/fwu/conf.py @@ -8,42 +8,34 @@ doc_info = { # Document template - 'template': 'psa-api-2025', + 'template': 'psa-api-2026', # Document title, MANDATORY 'title': 'PSA Certified\nFirmware Update API', 'author': 'Arm Limited', # Document copyright date, default to year of 'date' - 'copyright_date': '2020-2025', + 'copyright_date': '2020-2026', 'copyright': 'Arm Limited and/or its affiliates', - # Arm document identifier, marked as open issue if not provided - 'doc_id': 'IHI 0093', + # Document identifier, marked as open issue if not provided + 'doc_id': 'GPD_SPE_093', # The short X.Y version. MANDATORY 'version': '1.0', - # Arm document quality status, marked as open issue if not provided - 'quality': 'REL', - # Arm document issue number (within that version and quality status) - # Marked as open issue if not provided + # Document maintenance revision 'issue_no': 1, - # Identifies the sequence number of a release candidate of the same issue - # default to None - #'release_candidate': 2, - #'draft': True, - - # Arm document confidentiality. Must be either Non-confidential or Confidential - # Marked as open issue if not provided - 'confidentiality': 'Non-confidential', + # Document draft revision + 'draft': 1, + # Document status + 'status': 'DFT', # Id of the legal notice for this document # Marked as open issue if not provided - 'license': 'psa-certified-api-license', + #'license': 'psa-certified-api-license', # Document date, default to build date - 'date': '23/9/2025', - + 'date': 'September 2025', # psa_spec: default header file for API definitions # default to None, and can be set in documentation source @@ -73,14 +65,12 @@ 'page_break': 'chapter', } -# absolute or relative path to the psa_spec material from this file -atg_sphinx_spec_dir = '../atg-sphinx-spec' - -# Set up and run the atg-sphinx-spec configuration +# Set up and run the psa-api-tool configuration import os -atg_sphinx_spec_dir = os.environ.get('ATG_SPHINX_SPEC') or atg_sphinx_spec_dir -exec(compile(open(os.path.join(atg_sphinx_spec_dir,'atg-sphinx-conf.py'), +psa_api_tool_path = os.path.normpath(os.path.join(os.path.dirname(__file__), '..', '..', 'tools')) +psa_api_tool_path = os.environ.get('PSA_API_TOOL') or psa_api_tool_path +exec(compile(open(os.path.join(psa_api_tool_path,'psa-api-conf.py'), encoding='utf-8').read(), - 'atg-sphinx-conf.py', 'exec')) + 'psa-api-conf.py', 'exec')) diff --git a/doc/fwu/figure/arch/components.pdf b/doc/fwu/figure/arch/components.pdf index a4d6def0..2f30e1dd 100644 Binary files a/doc/fwu/figure/arch/components.pdf and b/doc/fwu/figure/arch/components.pdf differ diff --git a/doc/fwu/figure/arch/components.puml b/doc/fwu/figure/arch/components.puml index c8314680..78af628b 100644 --- a/doc/fwu/figure/arch/components.puml +++ b/doc/fwu/figure/arch/components.puml @@ -3,31 +3,31 @@ @startuml -!include atg-spec.pumh -!include atg-dataflow.pumh +!include psa-spec.pumh +!include psa-dataflow.pumh skinparam RectangleborderThickness 0 skinparam RectanglefontColor white -skinparam DatabaseBorderColor #ArmMidGray -skinparam InterfaceBorderColor #ArmMidGray +skinparam DatabaseBorderColor #PSAMidGray +skinparam InterfaceBorderColor #PSAMidGray -rectangle "Firmware creator" as creator #ArmDarkBlue +rectangle "Firmware creator" as creator #PSADarkBlue cloud Internet { - rectangle "Update server" as server #ArmMidGray + rectangle "Update server" as server #PSAMidGray } -interface "MQTT\n CoAP\nHTTPS\n ..." as tls #ArmLightGray +interface "MQTT\n CoAP\nHTTPS\n ..." as tls #PSALightGray dfd_tb("Device ") { - rectangle "Update client" as client #ArmMidGray - interface " **Firmware**\n**Update API**" as api #ArmGreen - rectangle "Update service" as service #ArmMidBlue - database "Firmware store" as store #ArmLightGray - rectangle "Bootloader" as bootloader #ArmMidBlue + rectangle "Update client" as client #PSAMidGray + interface " **Firmware**\n**Update API**" as api #PSAGreen + rectangle "Update service" as service #PSAMidBlue + database "Firmware store" as store #PSALightGray + rectangle "Bootloader" as bootloader #PSAMidBlue label " <&key>\nTrust anchor" as anchor } -database "External storage" as drive #ArmLightGray -interface "USB" as usb #ArmLightGray +database "External storage" as drive #PSALightGray +interface "USB" as usb #PSALightGray creator -> server server <- tls diff --git a/doc/fwu/figure/arch/components.svg b/doc/fwu/figure/arch/components.svg index 78b790db..146d22cf 100644 --- a/doc/fwu/figure/arch/components.svg +++ b/doc/fwu/figure/arch/components.svg @@ -1 +1 @@ -Internet«Device»Update serverUpdate client  FirmwareUpdate APIUpdate serviceFirmware storeBootloader   Trust anchorFirmware creatorMQTTCoAPHTTPS...External storageUSB \ No newline at end of file +Internet«Device»Update serverUpdate client  FirmwareUpdate APIUpdate serviceFirmware storeBootloader   Trust anchorFirmware creatorMQTTCoAPHTTPS...External storageUSB \ No newline at end of file diff --git a/doc/fwu/figure/arch/trusted-client.pdf b/doc/fwu/figure/arch/trusted-client.pdf index 518cf471..d13afc99 100644 Binary files a/doc/fwu/figure/arch/trusted-client.pdf and b/doc/fwu/figure/arch/trusted-client.pdf differ diff --git a/doc/fwu/figure/arch/trusted-client.puml b/doc/fwu/figure/arch/trusted-client.puml index f25404c5..4576ad8d 100644 --- a/doc/fwu/figure/arch/trusted-client.puml +++ b/doc/fwu/figure/arch/trusted-client.puml @@ -3,23 +3,23 @@ @startuml -!include atg-spec.pumh -!include atg-dataflow.pumh +!include psa-spec.pumh +!include psa-dataflow.pumh skinparam RectangleborderThickness 0 skinparam RectanglefontColor white skinparam FilefontColor white -skinparam DatabaseBorderColor #ArmMidGray -skinparam InterfaceBorderColor #ArmMidGray +skinparam DatabaseBorderColor #PSAMidGray +skinparam InterfaceBorderColor #PSAMidGray -file "Firmware package" <> as firmware #ArmDarkBlue +file "Firmware package" <> as firmware #PSADarkBlue dfd_tb($label = "Device") { - rectangle "Update client" <> as client #ArmMidGray - interface " **Firmware**\n**Update API**" as api #ArmGreen - rectangle "Update service" <> as service #ArmMidBlue - database "Firmware store" as store #ArmLightGray - rectangle "Bootloader" as bootloader #ArmMidBlue + rectangle "Update client" <> as client #PSAMidGray + interface " **Firmware**\n**Update API**" as api #PSAGreen + rectangle "Update service" <> as service #PSAMidBlue + database "Firmware store" as store #PSALightGray + rectangle "Bootloader" as bootloader #PSAMidBlue label " <&key>\nTrust anchor" as anchor } diff --git a/doc/fwu/figure/arch/trusted-client.svg b/doc/fwu/figure/arch/trusted-client.svg index cba64788..fbf0ec21 100644 --- a/doc/fwu/figure/arch/trusted-client.svg +++ b/doc/fwu/figure/arch/trusted-client.svg @@ -1 +1 @@ -«trust boundary»Device«app»Update client  FirmwareUpdate API«library»Update serviceFirmware storeBootloader   Trust anchor«data»Firmware package \ No newline at end of file +«trust boundary»Device«app»Update client  FirmwareUpdate API«library»Update serviceFirmware storeBootloader   Trust anchor«data»Firmware package \ No newline at end of file diff --git a/doc/fwu/figure/arch/untrusted-client.pdf b/doc/fwu/figure/arch/untrusted-client.pdf index 8ad775ef..2c6eb9cc 100644 Binary files a/doc/fwu/figure/arch/untrusted-client.pdf and b/doc/fwu/figure/arch/untrusted-client.pdf differ diff --git a/doc/fwu/figure/arch/untrusted-client.puml b/doc/fwu/figure/arch/untrusted-client.puml index e5d0512b..552cf9ac 100644 --- a/doc/fwu/figure/arch/untrusted-client.puml +++ b/doc/fwu/figure/arch/untrusted-client.puml @@ -3,27 +3,27 @@ @startuml -!include atg-spec.pumh -!include atg-dataflow.pumh +!include psa-spec.pumh +!include psa-dataflow.pumh skinparam RectangleborderThickness 0 skinparam RectanglefontColor white skinparam FilefontColor white -skinparam DatabaseBorderColor #ArmMidGray -skinparam InterfaceBorderColor #ArmMidGray +skinparam DatabaseBorderColor #PSAMidGray +skinparam InterfaceBorderColor #PSAMidGray -file "Firmware package" <> as firmware #ArmDarkBlue +file "Firmware package" <> as firmware #PSADarkBlue dfd_tb($label = "Device") { dfd_align() { - rectangle "Update client" <> as client #ArmMidGray - interface " **Firmware**\n**Update API**" as api #ArmGreen - rectangle "Update service proxy" <> as proxy #ArmMidBlue + rectangle "Update client" <> as client #PSAMidGray + interface " **Firmware**\n**Update API**" as api #PSAGreen + rectangle "Update service proxy" <> as proxy #PSAMidBlue } dfd_tb($label = "Platform Root of Trust") as rot { - rectangle "Update service" <> as service #ArmMidBlue - database "Firmware store" as store #ArmLightGray - rectangle "Bootloader" as bootloader #ArmMidBlue + rectangle "Update service" <> as service #PSAMidBlue + database "Firmware store" as store #PSALightGray + rectangle "Bootloader" as bootloader #PSAMidBlue label " <&key>\nTrust anchor" as anchor } } diff --git a/doc/fwu/figure/arch/untrusted-client.svg b/doc/fwu/figure/arch/untrusted-client.svg index f9c38d69..cb2b767e 100644 --- a/doc/fwu/figure/arch/untrusted-client.svg +++ b/doc/fwu/figure/arch/untrusted-client.svg @@ -1 +1 @@ -«trust boundary»Device«trust boundary»Platform Root of Trust«app»Update client  FirmwareUpdate API«library»Update service proxy«RoT service»Update serviceFirmware storeBootloader   Trust anchor«data»Firmware package \ No newline at end of file +«trust boundary»Device«trust boundary»Platform Root of Trust«app»Update client  FirmwareUpdate API«library»Update service proxy«RoT service»Update serviceFirmware storeBootloader   Trust anchor«data»Firmware package \ No newline at end of file diff --git a/doc/fwu/figure/arch/untrusted-staging.pdf b/doc/fwu/figure/arch/untrusted-staging.pdf index 1ab0879c..f31e3889 100644 Binary files a/doc/fwu/figure/arch/untrusted-staging.pdf and b/doc/fwu/figure/arch/untrusted-staging.pdf differ diff --git a/doc/fwu/figure/arch/untrusted-staging.puml b/doc/fwu/figure/arch/untrusted-staging.puml index c5c6ec95..be1aedce 100644 --- a/doc/fwu/figure/arch/untrusted-staging.puml +++ b/doc/fwu/figure/arch/untrusted-staging.puml @@ -3,27 +3,27 @@ @startuml -!include atg-spec.pumh -!include atg-dataflow.pumh +!include psa-spec.pumh +!include psa-dataflow.pumh skinparam RectangleborderThickness 0 skinparam RectanglefontColor white skinparam FilefontColor white -skinparam DatabaseBorderColor #ArmMidGray -skinparam InterfaceBorderColor #ArmMidGray +skinparam DatabaseBorderColor #PSAMidGray +skinparam InterfaceBorderColor #PSAMidGray -file "Firmware package" <> as firmware #ArmDarkBlue +file "Firmware package" <> as firmware #PSADarkBlue dfd_tb($label = "Device") { dfd_align() { - rectangle "Update client" <> as client #ArmMidGray - interface " **Firmware**\n**Update API**" as api #ArmGreen - rectangle "Update service" <> as service #ArmMidBlue - database "Staging area" as second #ArmLightGray + rectangle "Update client" <> as client #PSAMidGray + interface " **Firmware**\n**Update API**" as api #PSAGreen + rectangle "Update service" <> as service #PSAMidBlue + database "Staging area" as second #PSALightGray } dfd_tb($label = "Platform Root of Trust") { - database "//active// image" as active #ArmLightGray - rectangle "Bootloader" as bootloader #ArmMidBlue + database "//active// image" as active #PSALightGray + rectangle "Bootloader" as bootloader #PSAMidBlue label " <&key>\nTrust anchor" as anchor } } diff --git a/doc/fwu/figure/arch/untrusted-staging.svg b/doc/fwu/figure/arch/untrusted-staging.svg index 400834c2..ac66d730 100644 --- a/doc/fwu/figure/arch/untrusted-staging.svg +++ b/doc/fwu/figure/arch/untrusted-staging.svg @@ -1 +1 @@ -«trust boundary»Device«trust boundary»Platform Root of Trust«app»Update client  FirmwareUpdate API«library»Update serviceStaging areaactiveimageBootloader   Trust anchor«data»Firmware package \ No newline at end of file +«trust boundary»Device«trust boundary»Platform Root of Trust«app»Update client  FirmwareUpdate API«library»Update serviceStaging areaactiveimageBootloader   Trust anchor«data»Firmware package \ No newline at end of file diff --git a/doc/fwu/figure/intro/context.pdf b/doc/fwu/figure/intro/context.pdf index b20b5964..9ddadfec 100644 Binary files a/doc/fwu/figure/intro/context.pdf and b/doc/fwu/figure/intro/context.pdf differ diff --git a/doc/fwu/figure/intro/context.puml b/doc/fwu/figure/intro/context.puml index 971ecb5a..716b93cb 100644 --- a/doc/fwu/figure/intro/context.puml +++ b/doc/fwu/figure/intro/context.puml @@ -3,23 +3,23 @@ @startuml -!include atg-spec.pumh -!include atg-dataflow.pumh +!include psa-spec.pumh +!include psa-dataflow.pumh skinparam RectangleborderThickness 0 skinparam RectanglefontColor white -skinparam DatabaseBorderColor #ArmMidGray -skinparam InterfaceBorderColor #ArmMidGray +skinparam DatabaseBorderColor #PSAMidGray +skinparam InterfaceBorderColor #PSAMidGray -rectangle "Firmware creator" as creator #ArmDarkBlue +rectangle "Firmware creator" as creator #PSADarkBlue cloud Internet { - rectangle "Update server" as server #ArmMidGray + rectangle "Update server" as server #PSAMidGray } -interface "MQTT\n CoAP\nHTTPS\n ..." as tls #ArmLightGray +interface "MQTT\n CoAP\nHTTPS\n ..." as tls #PSALightGray dfd_tb("Device ") { - rectangle "Update client" as client #ArmMidBlue - database "Firmware store" as store #ArmLightGray + rectangle "Update client" as client #PSAMidBlue + database "Firmware store" as store #PSALightGray } creator -> server diff --git a/doc/fwu/figure/intro/context.svg b/doc/fwu/figure/intro/context.svg index 506c2cd9..50c71788 100644 --- a/doc/fwu/figure/intro/context.svg +++ b/doc/fwu/figure/intro/context.svg @@ -1 +1 @@ -Internet«Device»Update serverUpdate clientFirmware storeFirmware creatorMQTTCoAPHTTPS... \ No newline at end of file +Internet«Device»Update serverUpdate clientFirmware storeFirmware creatorMQTTCoAPHTTPS... \ No newline at end of file diff --git a/doc/fwu/figure/intro/fwu-api.pdf b/doc/fwu/figure/intro/fwu-api.pdf index c93c4e68..5a45ee75 100644 Binary files a/doc/fwu/figure/intro/fwu-api.pdf and b/doc/fwu/figure/intro/fwu-api.pdf differ diff --git a/doc/fwu/figure/intro/fwu-api.puml b/doc/fwu/figure/intro/fwu-api.puml index d258e686..e3346d98 100644 --- a/doc/fwu/figure/intro/fwu-api.puml +++ b/doc/fwu/figure/intro/fwu-api.puml @@ -3,26 +3,26 @@ @startuml -!include atg-spec.pumh -!include atg-dataflow.pumh +!include psa-spec.pumh +!include psa-dataflow.pumh skinparam RectangleborderThickness 0 skinparam RectanglefontColor white -skinparam DatabaseBorderColor #ArmMidGray -skinparam InterfaceBorderColor #ArmMidGray +skinparam DatabaseBorderColor #PSAMidGray +skinparam InterfaceBorderColor #PSAMidGray -rectangle "Firmware creator" as creator #ArmDarkBlue +rectangle "Firmware creator" as creator #PSADarkBlue cloud Internet { - rectangle "Update server" as server #ArmMidGray + rectangle "Update server" as server #PSAMidGray } -interface "MQTT\n CoAP\nHTTPS\n ..." as tls #ArmLightGray +interface "MQTT\n CoAP\nHTTPS\n ..." as tls #PSALightGray dfd_tb("Device ") { - rectangle "Update client" as client #ArmMidGray - interface " **Firmware**\n**Update API**" as api #ArmGreen - rectangle "Update service" as service #ArmMidBlue - database "Firmware store" as store #ArmLightGray - rectangle "Bootloader" as bootloader #ArmMidBlue + rectangle "Update client" as client #PSAMidGray + interface " **Firmware**\n**Update API**" as api #PSAGreen + rectangle "Update service" as service #PSAMidBlue + database "Firmware store" as store #PSALightGray + rectangle "Bootloader" as bootloader #PSAMidBlue } creator -> server diff --git a/doc/fwu/figure/intro/fwu-api.svg b/doc/fwu/figure/intro/fwu-api.svg index 009cd9db..e2c564de 100644 --- a/doc/fwu/figure/intro/fwu-api.svg +++ b/doc/fwu/figure/intro/fwu-api.svg @@ -1 +1 @@ -Internet«Device»Update serverUpdate client  FirmwareUpdate APIUpdate serviceFirmware storeBootloaderFirmware creatorMQTTCoAPHTTPS... \ No newline at end of file +Internet«Device»Update serverUpdate client  FirmwareUpdate APIUpdate serviceFirmware storeBootloaderFirmware creatorMQTTCoAPHTTPS... \ No newline at end of file diff --git a/doc/fwu/figure/sequence.pdf b/doc/fwu/figure/sequence.pdf index 64f7947a..1e76a697 100644 Binary files a/doc/fwu/figure/sequence.pdf and b/doc/fwu/figure/sequence.pdf differ diff --git a/doc/fwu/figure/sequence.puml b/doc/fwu/figure/sequence.puml index 19109bc8..5262ddd9 100644 --- a/doc/fwu/figure/sequence.puml +++ b/doc/fwu/figure/sequence.puml @@ -3,7 +3,7 @@ @startuml -!include atg-spec.pumh +!include psa-spec.pumh participant "Update server" as server participant "Update client" as client diff --git a/doc/fwu/figure/sequence.svg b/doc/fwu/figure/sequence.svg index 1dd708df..a857f4ab 100644 --- a/doc/fwu/figure/sequence.svg +++ b/doc/fwu/figure/sequence.svg @@ -1 +1 @@ -Update serverUpdate clientUpdate serviceFirmware storeBootloaderUpdate serverUpdate clientUpdate serviceFirmware storeBootloaderIn READY stateGet information about a componentpsa_fwu_query(component_id)Firmware informationNotify that an update is availablepsa_fwu_start(component_id)Set WRITING stateloop[while image is downloading]Download block of imagepsa_fwu_write(component_id, ...)Write block to imagepsa_fwu_finish(component_id)Set CANDIDATE stateReport download completeRequest to apply updatepsa_fwu_install()Check imagealt[dependency needed]PSA_ERROR_DEPENDENCY_NEEDED[fail firmware image checks]Set FAILED statePSA_ERROR_INVALID_ARGUMENT[all dependencies met]Set STAGED statePSA_SUCCESS_REBOOTpsa_fwu_request_reboot()System restartsVerify new imagealt[verification fails]Set FAILED state[verification succeeds]Install new imageSet TRIAL stateBoot imagealt[Component in TRIAL state]Test image functionalityalt[update is working properly]psa_fwu_accept()Set UPDATED state[testing fails]psa_fwu_reject()Set REJECTED statePSA_SUCCESS_REBOOTpsa_fwu_request_reboot()System restartsRestore previous imageSet FAILED stateBoot imageReport update statuspsa_fwu_clean(component_id)Erase store areaSet READY state \ No newline at end of file +Update serverUpdate clientUpdate serviceFirmware storeBootloaderUpdate serverUpdate clientUpdate serviceFirmware storeBootloaderIn READY stateGet information about a componentpsa_fwu_query(component_id)Firmware informationNotify that an update is availablepsa_fwu_start(component_id)Set WRITING stateloop[while image is downloading]Download block of imagepsa_fwu_write(component_id, ...)Write block to imagepsa_fwu_finish(component_id)Set CANDIDATE stateReport download completeRequest to apply updatepsa_fwu_install()Check imagealt[dependency needed]PSA_ERROR_DEPENDENCY_NEEDED[fail firmware image checks]Set FAILED statePSA_ERROR_INVALID_ARGUMENT[all dependencies met]Set STAGED statePSA_SUCCESS_REBOOTpsa_fwu_request_reboot()System restartsVerify new imagealt[verification fails]Set FAILED state[verification succeeds]Install new imageSet TRIAL stateBoot imagealt[Component in TRIAL state]Test image functionalityalt[update is working properly]psa_fwu_accept()Set UPDATED state[testing fails]psa_fwu_reject()Set REJECTED statePSA_SUCCESS_REBOOTpsa_fwu_request_reboot()System restartsRestore previous imageSet FAILED stateBoot imageReport update statuspsa_fwu_clean(component_id)Erase store areaSet READY state \ No newline at end of file diff --git a/doc/fwu/figure/sra/lifecycle.pdf b/doc/fwu/figure/sra/lifecycle.pdf index a487d858..89b0db6f 100644 Binary files a/doc/fwu/figure/sra/lifecycle.pdf and b/doc/fwu/figure/sra/lifecycle.pdf differ diff --git a/doc/fwu/figure/sra/lifecycle.puml b/doc/fwu/figure/sra/lifecycle.puml index aa6ec7e8..ec41710e 100644 --- a/doc/fwu/figure/sra/lifecycle.puml +++ b/doc/fwu/figure/sra/lifecycle.puml @@ -3,8 +3,8 @@ @startuml -!include atg-spec.pumh -!include atg-lifecycle.pumh +!include psa-spec.pumh +!include psa-lifecycle.pumh stakeholder "SiP and OEM" as k1 stakeholder "SiP, OEM,\nand/or Owner" as k2 diff --git a/doc/fwu/figure/sra/lifecycle.svg b/doc/fwu/figure/sra/lifecycle.svg index 7dc33d30..a3fcba2a 100644 --- a/doc/fwu/figure/sra/lifecycle.svg +++ b/doc/fwu/figure/sra/lifecycle.svg @@ -1 +1 @@ -ManufacturingOperationEnd of lifeSystemmanufacturingand initializationProvision ofauthorizationcredentialsBoot(Install update)Operation(Prepare update)ResetReturn toManufacturerSiP and OEMSiP, OEM,and/or Owner[everybody]SiP, OEM,and Owner \ No newline at end of file +ManufacturingOperationEnd of lifeSystemmanufacturingand initializationProvision ofauthorizationcredentialsBoot(Install update)Operation(Prepare update)ResetReturn toManufacturerSiP and OEMSiP, OEM,and/or Owner[everybody]SiP, OEM,and Owner \ No newline at end of file diff --git a/doc/fwu/figure/states/default.pdf b/doc/fwu/figure/states/default.pdf index 2ff934e2..90e5b013 100644 Binary files a/doc/fwu/figure/states/default.pdf and b/doc/fwu/figure/states/default.pdf differ diff --git a/doc/fwu/figure/states/default.puml b/doc/fwu/figure/states/default.puml index 8ad98abb..fb16f403 100644 --- a/doc/fwu/figure/states/default.puml +++ b/doc/fwu/figure/states/default.puml @@ -4,7 +4,7 @@ @startuml ' State diagram -!include atg-spec.pumh +!include psa-spec.pumh legend **Transitions** diff --git a/doc/fwu/figure/states/default.svg b/doc/fwu/figure/states/default.svg index 9b11b291..285b4ba1 100644 --- a/doc/fwu/figure/states/default.svg +++ b/doc/fwu/figure/states/default.svg @@ -1 +1 @@ -READYWRITING †CANDIDATESTAGED *FAILED ‡REJECTED *TRIAL *UPDATED ‡READYstartwritefinishcancelinstallcancelreboot:install successreboot:install failedrejectacceptcleanrejectreboot:rollbackreboot:rollbackcleanTransitions———Applies to a single component———Applies to all components---Transition overreboot. Volatile states*Always:reboottransition as shownOptional:rebootis equivalent tocancelandcleanOptional:rebootis equivalent toclean \ No newline at end of file +READYWRITING †CANDIDATESTAGED *FAILED ‡REJECTED *TRIAL *UPDATED ‡READYstartwritefinishcancelinstallcancelreboot:install successreboot:install failedrejectacceptcleanrejectreboot:rollbackreboot:rollbackcleanTransitions———Applies to a single component———Applies to all components---Transition overreboot. Volatile states*Always:reboottransition as shownOptional:rebootis equivalent tocancelandcleanOptional:rebootis equivalent toclean \ No newline at end of file diff --git a/doc/fwu/figure/states/no-reboot-no-trial-volatile.pdf b/doc/fwu/figure/states/no-reboot-no-trial-volatile.pdf index f9fabcc5..cfd20181 100644 Binary files a/doc/fwu/figure/states/no-reboot-no-trial-volatile.pdf and b/doc/fwu/figure/states/no-reboot-no-trial-volatile.pdf differ diff --git a/doc/fwu/figure/states/no-reboot-no-trial-volatile.puml b/doc/fwu/figure/states/no-reboot-no-trial-volatile.puml index 3910f448..3e66a0f7 100644 --- a/doc/fwu/figure/states/no-reboot-no-trial-volatile.puml +++ b/doc/fwu/figure/states/no-reboot-no-trial-volatile.puml @@ -4,7 +4,7 @@ @startuml '' State diagram -!include atg-spec.pumh +!include psa-spec.pumh skinparam LegendFontSize 12 diff --git a/doc/fwu/figure/states/no-reboot-no-trial-volatile.svg b/doc/fwu/figure/states/no-reboot-no-trial-volatile.svg index cabdb13a..bb1fbc5f 100644 --- a/doc/fwu/figure/states/no-reboot-no-trial-volatile.svg +++ b/doc/fwu/figure/states/no-reboot-no-trial-volatile.svg @@ -1 +1 @@ -READYWRITING †CANDIDATE †FAILED ‡UPDATED ‡READYstartwritefinishcancelinstall:install successcancelcleancleanTransitions———Applies to a single component———Applies to all components Volatile statesAlways:rebootis equivalent tocancelandcleanAlways:rebootis equivalent toclean \ No newline at end of file +READYWRITING †CANDIDATE †FAILED ‡UPDATED ‡READYstartwritefinishcancelinstall:install successcancelcleancleanTransitions———Applies to a single component———Applies to all components Volatile statesAlways:rebootis equivalent tocancelandcleanAlways:rebootis equivalent toclean \ No newline at end of file diff --git a/doc/fwu/figure/states/no-reboot-no-trial.pdf b/doc/fwu/figure/states/no-reboot-no-trial.pdf index 0b27fe23..e5073fbb 100644 Binary files a/doc/fwu/figure/states/no-reboot-no-trial.pdf and b/doc/fwu/figure/states/no-reboot-no-trial.pdf differ diff --git a/doc/fwu/figure/states/no-reboot-no-trial.puml b/doc/fwu/figure/states/no-reboot-no-trial.puml index cb778517..dcafbc39 100644 --- a/doc/fwu/figure/states/no-reboot-no-trial.puml +++ b/doc/fwu/figure/states/no-reboot-no-trial.puml @@ -4,7 +4,7 @@ @startuml '' State diagram -!include atg-spec.pumh +!include psa-spec.pumh skinparam LegendFontSize 12 diff --git a/doc/fwu/figure/states/no-reboot-no-trial.svg b/doc/fwu/figure/states/no-reboot-no-trial.svg index 65a15b85..3d1883a1 100644 --- a/doc/fwu/figure/states/no-reboot-no-trial.svg +++ b/doc/fwu/figure/states/no-reboot-no-trial.svg @@ -1 +1 @@ -READYWRITING †CANDIDATEFAILED ‡UPDATED ‡READYstartwritefinishcancelinstall:install successcancelcleancleanTransitions———Applies to a single component———Applies to all components Volatile statesOptional:rebootis equivalent tocancelandcleanOptional:rebootis equivalent toclean \ No newline at end of file +READYWRITING †CANDIDATEFAILED ‡UPDATED ‡READYstartwritefinishcancelinstall:install successcancelcleancleanTransitions———Applies to a single component———Applies to all components Volatile statesOptional:rebootis equivalent tocancelandcleanOptional:rebootis equivalent toclean \ No newline at end of file diff --git a/doc/fwu/figure/states/no-reboot-volatile.pdf b/doc/fwu/figure/states/no-reboot-volatile.pdf index 682524a0..3fa63cc0 100644 Binary files a/doc/fwu/figure/states/no-reboot-volatile.pdf and b/doc/fwu/figure/states/no-reboot-volatile.pdf differ diff --git a/doc/fwu/figure/states/no-reboot-volatile.puml b/doc/fwu/figure/states/no-reboot-volatile.puml index d8b3ebf6..beadf9d0 100644 --- a/doc/fwu/figure/states/no-reboot-volatile.puml +++ b/doc/fwu/figure/states/no-reboot-volatile.puml @@ -4,7 +4,7 @@ @startuml '' State diagram -!include atg-spec.pumh +!include psa-spec.pumh skinparam LegendFontSize 12 diff --git a/doc/fwu/figure/states/no-reboot-volatile.svg b/doc/fwu/figure/states/no-reboot-volatile.svg index f42b74df..913b5249 100644 --- a/doc/fwu/figure/states/no-reboot-volatile.svg +++ b/doc/fwu/figure/states/no-reboot-volatile.svg @@ -1 +1 @@ -READYWRITING †CANDIDATE †FAILED ‡TRIAL *UPDATED ‡READYstartwritefinishcancelinstall:install successcancelacceptcleanrejectcleanTransitions———Applies to a single component———Applies to all components Volatile states*Always:rebootis equivalent torejectandcleanAlways:rebootis equivalent tocancelandcleanAlways:rebootis equivalent toclean \ No newline at end of file +READYWRITING †CANDIDATE †FAILED ‡TRIAL *UPDATED ‡READYstartwritefinishcancelinstall:install successcancelacceptcleanrejectcleanTransitions———Applies to a single component———Applies to all components Volatile states*Always:rebootis equivalent torejectandcleanAlways:rebootis equivalent tocancelandcleanAlways:rebootis equivalent toclean \ No newline at end of file diff --git a/doc/fwu/figure/states/no-reboot.pdf b/doc/fwu/figure/states/no-reboot.pdf index 2e737251..485f9f35 100644 Binary files a/doc/fwu/figure/states/no-reboot.pdf and b/doc/fwu/figure/states/no-reboot.pdf differ diff --git a/doc/fwu/figure/states/no-reboot.puml b/doc/fwu/figure/states/no-reboot.puml index 33149c36..d193ce5c 100644 --- a/doc/fwu/figure/states/no-reboot.puml +++ b/doc/fwu/figure/states/no-reboot.puml @@ -4,7 +4,7 @@ @startuml '' State diagram -!include atg-spec.pumh +!include psa-spec.pumh skinparam LegendFontSize 12 diff --git a/doc/fwu/figure/states/no-reboot.svg b/doc/fwu/figure/states/no-reboot.svg index 1079b942..66ac2b70 100644 --- a/doc/fwu/figure/states/no-reboot.svg +++ b/doc/fwu/figure/states/no-reboot.svg @@ -1 +1 @@ -READYWRITING †CANDIDATEFAILED ‡TRIALUPDATED ‡READYstartwritefinishcancelinstall:install successcancelacceptcleanrejectcleanTransitions———Applies to a single component———Applies to all components Volatile statesOptional:rebootis equivalent tocancelandcleanOptional:rebootis equivalent toclean \ No newline at end of file +READYWRITING †CANDIDATEFAILED ‡TRIALUPDATED ‡READYstartwritefinishcancelinstall:install successcancelacceptcleanrejectcleanTransitions———Applies to a single component———Applies to all components Volatile statesOptional:rebootis equivalent tocancelandcleanOptional:rebootis equivalent toclean \ No newline at end of file diff --git a/doc/fwu/figure/states/no-trial-volatile.pdf b/doc/fwu/figure/states/no-trial-volatile.pdf index 0ab658ba..9f098e3c 100644 Binary files a/doc/fwu/figure/states/no-trial-volatile.pdf and b/doc/fwu/figure/states/no-trial-volatile.pdf differ diff --git a/doc/fwu/figure/states/no-trial-volatile.puml b/doc/fwu/figure/states/no-trial-volatile.puml index f382ad6a..b477457d 100644 --- a/doc/fwu/figure/states/no-trial-volatile.puml +++ b/doc/fwu/figure/states/no-trial-volatile.puml @@ -4,7 +4,7 @@ @startuml '' State diagram -!include atg-spec.pumh +!include psa-spec.pumh skinparam LegendFontSize 12 diff --git a/doc/fwu/figure/states/no-trial-volatile.svg b/doc/fwu/figure/states/no-trial-volatile.svg index 2bff6000..c180857c 100644 --- a/doc/fwu/figure/states/no-trial-volatile.svg +++ b/doc/fwu/figure/states/no-trial-volatile.svg @@ -1 +1 @@ -READYWRITING †CANDIDATE †STAGED *FAILED ‡READYstartwritefinishcancelcancelinstallreboot:install successreboot:install failedrejectcleanTransitions———Applies to a single component———Applies to all components---Transition overreboot Volatile states*Always:reboottransition as shownAlways:rebootis equivalent tocancelandcleanAlways:rebootis equivalent toclean \ No newline at end of file +READYWRITING †CANDIDATE †STAGED *FAILED ‡READYstartwritefinishcancelcancelinstallreboot:install successreboot:install failedrejectcleanTransitions———Applies to a single component———Applies to all components---Transition overreboot Volatile states*Always:reboottransition as shownAlways:rebootis equivalent tocancelandcleanAlways:rebootis equivalent toclean \ No newline at end of file diff --git a/doc/fwu/figure/states/no-trial.pdf b/doc/fwu/figure/states/no-trial.pdf index 10381310..434991f7 100644 Binary files a/doc/fwu/figure/states/no-trial.pdf and b/doc/fwu/figure/states/no-trial.pdf differ diff --git a/doc/fwu/figure/states/no-trial.puml b/doc/fwu/figure/states/no-trial.puml index cde5f676..1055197b 100644 --- a/doc/fwu/figure/states/no-trial.puml +++ b/doc/fwu/figure/states/no-trial.puml @@ -4,7 +4,7 @@ @startuml '' State diagram -!include atg-spec.pumh +!include psa-spec.pumh skinparam LegendFontSize 12 diff --git a/doc/fwu/figure/states/no-trial.svg b/doc/fwu/figure/states/no-trial.svg index 1402e407..69a2beb3 100644 --- a/doc/fwu/figure/states/no-trial.svg +++ b/doc/fwu/figure/states/no-trial.svg @@ -1 +1 @@ -READYWRITING †CANDIDATESTAGED *FAILED ‡UPDATED ‡READYstartwritefinishcancelcancelinstallreboot:install successreboot:install failedrejectcleancleanTransitions———Applies to a single component———Applies to all components---Transition overreboot. Volatile states*Always:reboottransition as shownOptional:rebootis equivalent tocancelandcleanOptional:rebootis equivalent toclean \ No newline at end of file +READYWRITING †CANDIDATESTAGED *FAILED ‡UPDATED ‡READYstartwritefinishcancelcancelinstallreboot:install successreboot:install failedrejectcleancleanTransitions———Applies to a single component———Applies to all components---Transition overreboot. Volatile states*Always:reboottransition as shownOptional:rebootis equivalent tocancelandcleanOptional:rebootis equivalent toclean \ No newline at end of file diff --git a/doc/fwu/figure/states/volatile.pdf b/doc/fwu/figure/states/volatile.pdf index 15d170aa..ca19dd3b 100644 Binary files a/doc/fwu/figure/states/volatile.pdf and b/doc/fwu/figure/states/volatile.pdf differ diff --git a/doc/fwu/figure/states/volatile.puml b/doc/fwu/figure/states/volatile.puml index e8433398..16ef6079 100644 --- a/doc/fwu/figure/states/volatile.puml +++ b/doc/fwu/figure/states/volatile.puml @@ -4,7 +4,7 @@ @startuml ' State diagram -!include atg-spec.pumh +!include psa-spec.pumh skinparam LegendFontSize 12 diff --git a/doc/fwu/figure/states/volatile.svg b/doc/fwu/figure/states/volatile.svg index bad81ba1..0caf2dca 100644 --- a/doc/fwu/figure/states/volatile.svg +++ b/doc/fwu/figure/states/volatile.svg @@ -1 +1 @@ -READYWRITING †CANDIDATE †STAGED *FAILED ‡REJECTED *TRIAL *UPDATED ‡READYstartwritefinishcancelinstallcancelreboot:install successreboot:install failedrejectacceptcleanrejectreboot:rollbackreboot:rollbackcleanTransitions———Applies to a single component———Applies to all components---Transition overreboot Volatile states*Always:reboottransition as shownAlways:rebootis equivalent tocancelandcleanAlways:rebootis equivalent toclean \ No newline at end of file +READYWRITING †CANDIDATE †STAGED *FAILED ‡REJECTED *TRIAL *UPDATED ‡READYstartwritefinishcancelinstallcancelreboot:install successreboot:install failedrejectacceptcleanrejectreboot:rollbackreboot:rollbackcleanTransitions———Applies to a single component———Applies to all components---Transition overreboot Volatile states*Always:reboottransition as shownAlways:rebootis equivalent tocancelandcleanAlways:rebootis equivalent toclean \ No newline at end of file diff --git a/doc/fwu/index.rst b/doc/fwu/index.rst index f3717c89..35165999 100644 --- a/doc/fwu/index.rst +++ b/doc/fwu/index.rst @@ -3,21 +3,9 @@ .. title:: - .. banner:: - - This is a DRAFT release. The content is subject to change. To provide feedback, see :secref:`feedback`. - - .. abstract:: - - This document defines a standard firmware interface for installing firmware updates. - -.. front-matter:: - - about - .. maintoc:: - overview/intro + about/about overview/goals overview/architecture overview/programming-model diff --git a/doc/fwu/overview/goals.rst b/doc/fwu/overview/goals.rst index 020f731e..e69306c2 100644 --- a/doc/fwu/overview/goals.rst +++ b/doc/fwu/overview/goals.rst @@ -1,17 +1,61 @@ -.. SPDX-FileCopyrightText: Copyright 2020-2023 Arm Limited and/or its affiliates +.. SPDX-FileCopyrightText: Copyright 2020-2023, 2026 Arm Limited and/or its affiliates .. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license +.. _intro: + +Firmware update +=============== + +Connected devices need a reliable and secure firmware update mechanism. Incorporating such an update mechanism is a fundamental requirement for fixing vulnerabilities, but it also enables other important capabilities such as updating configuration settings and adding new functionality. This can be particularly challenging for devices with resource constraints, as highlighted in :rfc-title:`8240`. + +:numref:`fig-context` depicts the actors and agents involved in a typical firmware update scenario. + +.. figure:: /figure/intro/context.* + :name: fig-context + + A typical over-the-air firmware update scenario + +In this example, the new firmware is uploaded by the Firmware creator to an Update server. The Update server communicates with an Update client application on the device, announcing the availability of new firmware. The client downloads the new firmware, and installs it into the device firmware storage. + +In :numref:`fig-context`, the Update client has to combine the following capabilities: + +* The specific protocols used by the network operator in which the device is deployed +* The specific mechanism used by the hardware platform to install firmware for execution + +Devices developed for the Internet of Things (IoT) have a very diverse ecosystem of hardware and software developers, and utilize a broad set of communication protocols and technologies. This will lead to a large, fragmented set of Update clients, that are each tightly coupled to one hardware platform and one network protocol. + +The |API| separates the software responsible for delivering the new firmware in the device, from the software that is responsible for storing and installing it in the device memory. :numref:`fig-api` shows how the |API| separates an Update client, which obtains the new firmware from the Firmware Server, from an Update service, which stores the firmware in the device memory. + +.. figure:: /figure/intro/fwu-api.* + :name: fig-api + + The |API| + +In practice, this enables an Update client to be written independently of the firmware storage design, and the Update service to be written independently of the delivery mechanism. + +The remainder of this document includes: + +* The design goals for the |API|. See :secref:`design-goals`. +* A definition of the concepts and terminology used in this document. See :secref:`architecture`. +* A description of the interface design. See :secref:`programming-model`. +* A detailed definition of the API. See :secref:`api-reference`. + +The appendixes provide additional information: + +* A sample header file containing all of the API elements. See :secref:`appendix-example-header`. +* Some example code demonstrating various use cases. See :secref:`examples`. + .. _design-goals: Design goals -============ +------------ This section describes the main goals and use cases for the |API|. .. _goal-constrained: Suitable for constrained devices ---------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The interface is suitable for a range of embedded devices: from those with resource-limited microcontrollers with one or two simple firmware images, to richer devices that have firmware images for multiple subsystems and separated applications. @@ -38,7 +82,7 @@ For example, the following resource constraints can affect the |API|: For devices with sufficient resources, it is recommended to follow the :cite-title:`EBBR` specification, which prescribes the :cite-title:`UEFI` capsule update interface. Updating the Platform Root of Trust ------------------------------------ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The |API| is suitable for updating the device's :term:`Platform Root of Trust` (PRoT) firmware. @@ -51,12 +95,12 @@ The :cite:`PSM` requirements for firmware update are also reflected in publicati The TOE also rejects attempts of firmware downgrade. Updating the Application Root of Trust --------------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In addition to the PRoT firmware, other services that run in the :term:`Secure processing environment` (SPE), but outside of the PRoT, can require update via the |API|. These services may be combined with the updatable PRoT in a single firmware image, or provided in a separate firmware image. Flexibility for different trust models ---------------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ There are a number of factors that impact the trust model that is used to authorize device updates and firmware execution. For example: @@ -67,7 +111,7 @@ There are a number of factors that impact the trust model that is used to author The |API| must be flexible enough to support the trust model required for particular products, without imposing unnecessary overheads on constrained devices. Protocol independence ---------------------- +~~~~~~~~~~~~~~~~~~~~~ Different protocols are used to communicate with a device depending on the industry and application context. This includes open protocols, such as :cite-title:`LWM2M`, and proprietary protocols from cloud service providers. These protocols serve the specific needs of their respective markets. @@ -76,7 +120,7 @@ Some of the protocols have :term:`manifest` data that is separate from the firmw The |API| must be independent of the protocol used by the update client to receive an update. Transport independence ----------------------- +~~~~~~~~~~~~~~~~~~~~~~ Embedded devices can receive over-the-air (OTA) firmware updates over different transport technologies, depending on the industry and the application. For example, this includes Wi-Fi, LTE, LoRa, and commercial low-power wide-area networks. @@ -89,7 +133,7 @@ The |API| must be independent of the transport used by the update client to rece The |API| does not cover reprogramming of a device using a debug interface, for example, JTAG or SWD. Firmware format independence ----------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Many device manufacturers and cloud service providers have established formats for firmware images and manifests, tailored to the specific needs of their systems and markets. @@ -101,10 +145,10 @@ The |API| must be independent of the format and encoding of firmware images and This version of the |API| is suitable for some of the use cases that are defined by :rfc-title:`9124` and :cite-title:`SUIT-MFST`. For example, where the payloads are integrated in the manifest envelope, or there is just one external payload to the envelope. - Support for the more complex use cases from :rfc:`9124`, with multiple external payloads, is not considered in version |docversion| of the |API|, but might be in scope for future versions of the interface. + Support for the more complex use cases from :rfc:`9124`, with multiple external payloads, is not considered in version |APIversion| of the |API|, but might be in scope for future versions of the interface. Flexibility for different hardware designs ------------------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The |API| is designed to be reasonably efficient to implement on different system-on-chip (SoC) architectures, while providing a consistent interface for update clients to target. @@ -118,14 +162,14 @@ For example, the |API| should be effective in the following types of system: * Systems that have a mixture of on-chip and external non-volatile memory used for firmware storage. Suitable for composite devices ------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Some platforms have independent subsystems that are isolated from the main microprocessor. These subsystems can have their own firmware, which can also require updates. For example, radios, secure elements, secure enclaves, or other kinds of microcontroller. The |API| must support an implementation updates these types of subsystem. Robust and reliable update --------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~ Devices that are remotely deployed, or are deployed in large numbers, must use an update process that does not have routine failure modes that result in devices that cannot be remotely recovered. @@ -138,7 +182,7 @@ The |API| must support an update process that reduces the risk of in-field updat The |API| might be useful for implementation of recovery firmware, but the requirements of recovery firmware are not considered in the interface design. Flexibility in implementation design ------------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The |API| is architectural and does not define a single implementation. An implementation can make trade-offs to target specific device needs. For example: diff --git a/doc/fwu/overview/intro.rst b/doc/fwu/overview/intro.rst deleted file mode 100644 index 155135d2..00000000 --- a/doc/fwu/overview/intro.rst +++ /dev/null @@ -1,63 +0,0 @@ -.. SPDX-FileCopyrightText: Copyright 2020-2025 Arm Limited and/or its affiliates -.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license - -Introduction -============ - -About Platform Security Architecture ------------------------------------- - -This document is one of a set of resources provided by Arm that can help organizations develop products that meet the security requirements of GlobalPlatform's PSA Certified evaluation scheme on Arm-based platforms. The PSA Certified scheme provides a framework and methodology that helps silicon manufacturers, system software providers and OEMs to develop more secure products. Arm resources that support PSA Certified range from threat models, standard architectures that simplify development and increase portability, and open-source partnerships that provide ready-to-use software. You can read more about PSA Certified here at :url:`www.psacertified.org` and find more Arm resources here at :url:`developer.arm.com/platform-security-resources` and :url:`www.trustedfirmware.org`. - -About the |API| ---------------- - -The interface described in this document is a PSA Certified API, that provides a portable programming interface to firmware update and installation operations on a wide range of hardware. - -The interface enables the software and systems that manage and deliver a firmware update to a device, to be developed independently from the hardware-specific mechanisms required to apply the update to the device. Reusing the deployment and delivery system for firmware updates reduces the complexity of providing firmware updates across a diverse set of managed devices. - -You can find additional resources relating to the |API| here at :url:`arm-software.github.io/psa-api/fwu`, and find other PSA Certified APIs here at :url:`arm-software.github.io/psa-api`. - -.. _intro: - -Firmware update ---------------- - -Connected devices need a reliable and secure firmware update mechanism. Incorporating such an update mechanism is a fundamental requirement for fixing vulnerabilities, but it also enables other important capabilities such as updating configuration settings and adding new functionality. This can be particularly challenging for devices with resource constraints, as highlighted in :rfc-title:`8240`. - -:numref:`fig-context` depicts the actors and agents involved in a typical firmware update scenario. - -.. figure:: /figure/intro/context.* - :name: fig-context - - A typical over-the-air firmware update scenario - -In this example, the new firmware is uploaded by the Firmware creator to an Update server. The Update server communicates with an Update client application on the device, announcing the availability of new firmware. The client downloads the new firmware, and installs it into the device firmware storage. - -In :numref:`fig-context`, the Update client has to combine the following capabilities: - -* The specific protocols used by the network operator in which the device is deployed -* The specific mechanism used by the hardware platform to install firmware for execution - -Devices developed for the Internet of Things (IoT) have a very diverse ecosystem of hardware and software developers, and utilize a broad set of communication protocols and technologies. This will lead to a large, fragmented set of Update clients, that are each tightly coupled to one hardware platform and one network protocol. - -The |API| separates the software responsible for delivering the new firmware in the device, from the software that is responsible for storing and installing it in the device memory. :numref:`fig-api` shows how the |API| separates an Update client, which obtains the new firmware from the Firmware Server, from an Update service, which stores the firmware in the device memory. - -.. figure:: /figure/intro/fwu-api.* - :name: fig-api - - The |API| - -In practice, this enables an Update client to be written independently of the firmware storage design, and the Update service to be written independently of the delivery mechanism. - -The remainder of this document includes: - -* The design goals for the |API|. See :secref:`design-goals`. -* A definition of the concepts and terminology used in this document. See :secref:`architecture`. -* A description of the interface design. See :secref:`programming-model`. -* A detailed definition of the API. See :secref:`api-reference`. - -The appendixes provide additional information: - -* A sample header file containing all of the API elements. See :secref:`appendix-example-header`. -* Some example code demonstrating various use cases. See :secref:`examples`. diff --git a/doc/fwu/pyproject.toml b/doc/fwu/pyproject.toml new file mode 100644 index 00000000..52de3a0e --- /dev/null +++ b/doc/fwu/pyproject.toml @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: Copyright 2026 Arm Limited and/or its affiliates +# SPDX-License-Identifier: Apache-2.0 + +[tool.esbonio] diff --git a/doc/status-code/about/about.rst b/doc/status-code/about/about.rst index 2a516c3b..d571f0f0 100644 --- a/doc/status-code/about/about.rst +++ b/doc/status-code/about/about.rst @@ -3,22 +3,10 @@ .. include:: releases -.. release-info:: - :replace: - - Prior to version 1.0.1, the definitions in this specification were released as part of :cite-title:`PSA-FFM`. - - The change history table lists the changes that have been made to this document. - - .. release-table:: Document revision history - - For a detailed list of changes, see :secref:`change-history`. - .. include:: references .. include:: terms -.. potential-for-change:: - :hide: +.. include:: intro .. about:: diff --git a/doc/status-code/about/intro b/doc/status-code/about/intro new file mode 100644 index 00000000..e4a24eca --- /dev/null +++ b/doc/status-code/about/intro @@ -0,0 +1,21 @@ +.. SPDX-FileCopyrightText: Copyright 2022, 2025-2026 Arm Limited and/or its affiliates +.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +.. introduction:: + + This document is one of a set of resources that can help organizations develop products that meet the security requirements of GlobalPlatform's PSA Certified evaluation scheme. The PSA Certified scheme provides a framework and methodology that helps silicon manufacturers, system software providers and OEMs to develop more secure products. You can read more about PSA Certified here at :url:`www.psacertified.org`. + + .. rubric:: About the |API| + + The interface described in this document is a PSA Certified API, that provides a shared set of interface definitions used by other PSA Certified APIs. + + You can find additional resources relating to the |API| here at :url:`arm-software.github.io/psa-api/status-code`, and find other PSA Certified APIs here at :url:`arm-software.github.io/psa-api`. + +.. audience:: + + This document is intended primarily for the use of developers of: + + * PSA Certified API specifications. + * Implementations of PSA Certified APIs. + * Frameworks that provide access to security services via the PSA Certified APIs. + * Client applications and Root of Trust Services that use any of the PSA Certified APIs. diff --git a/doc/status-code/about/references b/doc/status-code/about/references index d3a490cf..3ffe176a 100644 --- a/doc/status-code/about/references +++ b/doc/status-code/about/references @@ -1,12 +1,14 @@ -.. SPDX-FileCopyrightText: Copyright 2022, 2025 Arm Limited and/or its affiliates +.. SPDX-FileCopyrightText: Copyright 2022, 2026 Arm Limited and/or its affiliates .. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license -.. reference:: PSA-FFM +.. reference:: PSA FFM :title: Arm® Platform Security Architecture Firmware Framework - :doc_no: DEN 0063 + :kind: normative + :doc_id: Arm DEN 0063 :url: https://developer.arm.com/documentation/den0063/a .. reference:: TF-M :title: Trusted Firmware-M + :kind: informative :author: trustedfirmware.org :url: git.trustedfirmware.org/trusted-firmware-m.git/about/ diff --git a/doc/status-code/about/releases b/doc/status-code/about/releases index 4de207a7..2cbc5b98 100644 --- a/doc/status-code/about/releases +++ b/doc/status-code/about/releases @@ -34,3 +34,11 @@ :confidentiality: Non-confidential Fix link to PSA FF-M specification + + +.. release-info:: + :extend: + + Prior to version 1.0.1, the definitions in this specification were released as part of :cite-title:`PSA FFM`. + + For a detailed list of changes, see :secref:`change-history`. diff --git a/doc/status-code/about/terms b/doc/status-code/about/terms index 13a80e08..fee206ce 100644 --- a/doc/status-code/about/terms +++ b/doc/status-code/about/terms @@ -26,4 +26,4 @@ .. term:: Secure Partition Manager :abbr: SPM - Part of :cite-title:`PSA-FFM` that is responsible for isolating software in Partitions, managing the execution of software within Partitions, and providing communication between Partitions. + Part of :cite-title:`PSA FFM` that is responsible for isolating software in Partitions, managing the execution of software within Partitions, and providing communication between Partitions. diff --git a/doc/status-code/api/status-codes.rst b/doc/status-code/api/status-codes.rst index 94de2c51..b10dcefa 100644 --- a/doc/status-code/api/status-codes.rst +++ b/doc/status-code/api/status-codes.rst @@ -20,7 +20,7 @@ Status codes ``-129`` to ``-248`` are for use by PSA Certified API specification Status codes in this range must only be used as defined in a PSA specification. -In the context of an implementation of :cite-title:`PSA-FFM`: +In the context of an implementation of :cite-title:`PSA FFM`: * The :term:`Secure Partition Manager` (SPM) implementation can define error codes in the range ``-249`` to ``-256`` for :sc:`IMPLEMENTATION DEFINED` purposes. * A :term:`Root of Trust Service` (RoT Service) can define additional error codes in the ranges ``-1`` to ``-128`` and ``-257`` to ``MIN_INT32`` for RoT Service-specific error conditions. @@ -140,14 +140,14 @@ Error codes This error indicates that the function has detected an abnormal call, which typically indicates a programming error in the caller, or an abuse of the API. - This error has a specific meaning in an implementation of :cite-title:`PSA-FFM`. + This error has a specific meaning in an implementation of :cite-title:`PSA FFM`. .. macro:: PSA_ERROR_CONNECTION_REFUSED :definition: ((psa_status_t)-130) .. summary:: A status code that indicates that the caller is not permitted to connect to a Service. - This message has a specific meaning in an implementation of :cite-title:`PSA-FFM`. + This message has a specific meaning in an implementation of :cite-title:`PSA FFM`. .. macro:: PSA_ERROR_CONNECTION_BUSY @@ -155,7 +155,7 @@ Error codes .. summary:: A status code that indicates that the caller cannot connect to a service. - This message has a specific meaning in an implementation of :cite-title:`PSA-FFM`. + This message has a specific meaning in an implementation of :cite-title:`PSA FFM`. .. macro:: PSA_ERROR_GENERIC_ERROR diff --git a/doc/status-code/appendix/change-history.rst b/doc/status-code/appendix/change-history.rst index f93cf25a..a7992047 100644 --- a/doc/status-code/appendix/change-history.rst +++ b/doc/status-code/appendix/change-history.rst @@ -1,4 +1,4 @@ -.. SPDX-FileCopyrightText: Copyright 2022, 2024-2025 Arm Limited and/or its affiliates +.. SPDX-FileCopyrightText: Copyright 2022, 2024-2026 Arm Limited and/or its affiliates .. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license .. _change-history: @@ -7,11 +7,20 @@ Change history ============== +Document and API Changes +~~~~~~~~~~~~~~~~~~~~~~~~ + +Changes in the draft GlobalPlatform publication revision +-------------------------------------------------------- + +* Migrated the document to the 2026 PSA Certified API template. + + This changes the document front matter structure and publication styling, without changing the API. Changes between version 1.0.4 and version 1.0.5 ----------------------------------------------- -* Fixed the link in the :cite-title:`PSA-FFM` document reference. +* Fixed the link in the :cite-title:`PSA FFM` document reference. Changes between version 1.0.3 and version 1.0.4 ----------------------------------------------- @@ -26,7 +35,7 @@ Changes between version 1.0.2 and version 1.0.3 Changes between version 1.0.1 and version 1.0.2 ----------------------------------------------- -* Removed the whitespace within the definition of some of the status codes. The whitespace was erroneously introduced during the separation from the :cite-title:`PSA-FFM`. This change is necessary to ensure that multiple definitions of the same status code are identical, as required by the C language. +* Removed the whitespace within the definition of some of the status codes. The whitespace was erroneously introduced during the separation from the :cite-title:`PSA FFM`. This change is necessary to ensure that multiple definitions of the same status code are identical, as required by the C language. Changes between version 1.0.0 and version 1.0.1 @@ -47,4 +56,4 @@ Changes between version 1.0.0 and version 1.0.1 Changes prior to version 1.0.0 ------------------------------ -The definition of the common status codes was incorporated in the :cite-title:`PSA-FFM` specification up until version 1.0.0. +The definition of the common status codes was incorporated in the :cite-title:`PSA FFM` specification up until version 1.0.0. diff --git a/doc/status-code/conf.py b/doc/status-code/conf.py index 662997f5..b5462900 100644 --- a/doc/status-code/conf.py +++ b/doc/status-code/conf.py @@ -8,7 +8,7 @@ doc_info = { # Document template - 'template': 'psa-api-2025', + 'template': 'psa-api-2026', # Document title, MANDATORY 'title': 'PSA Certified\nStatus code API', @@ -18,31 +18,24 @@ 'copyright_date': '2017-2022, 2024-2026', 'copyright': 'Arm Limited and/or its affiliates', - # Arm document identifier, marked as open issue if not provided - 'doc_id': 'IHI 0097', + # Document identifier, marked as open issue if not provided + 'doc_id': 'GPD_SPE_097', # The short X.Y version. MANDATORY 'version': '1.0', - # Arm document quality status, marked as open issue if not provided - 'quality': 'REL', - # Arm document issue number (within that version and quality status) - # Marked as open issue if not provided + # Document maintenance revision 'issue_no': 5, - # Identifies the sequence number of a release candidate of the same issue - # default to None - 'release_candidate': None, - 'draft': False, - - # Arm document confidentiality. Must be either Non-confidential or Confidential - # Marked as open issue if not provided - 'confidentiality': 'Non-confidential', + # Document draft revision + 'draft': 1, + # Document status + 'status': 'DFT', # Id of the legal notice for this document # Marked as open issue if not provided - 'license': 'psa-certified-api-license', + #'license': 'psa-certified-api-license', # Document date, default to build date - 'date': '22/01/2026', + 'date': 'January 2026', # psa_spec: default header file for API definitions # default to None, and can be set in documentation source @@ -63,7 +56,7 @@ 'include_content': [], # Include the C Identifier index. Default to True - 'identifier_index': False, + 'identifier_index': True, # Specify where to add page breaks in main/appendix # 'none' : no page breaks @@ -73,26 +66,12 @@ 'page_break': 'chapter', } -# If the draft flag is set, then include extra content and watermark - -if doc_info.get('draft'): - doc_info.pop('date', None) # Remove any release date - use build date - doc_info['include_content'] = ['rationale', 'todo', 'banner'] - doc_info['watermark'] = "DRAFT" - -# If a release candidate, then include watermark - -if doc_info.get('release_candidate'): - doc_info['watermark'] = "Candidate" - -# absolute or relative path to the psa_spec material from this file -# atg_sphinx_spec_dir = '../atg-sphinx-spec' - -# Set up and run the atg-sphinx-spec configuration +# Set up and run the psa-api-tool configuration import os -atg_sphinx_spec_dir = os.environ.get('ATG_SPHINX_SPEC') or atg_sphinx_spec_dir -exec(compile(open(os.path.join(atg_sphinx_spec_dir,'atg-sphinx-conf.py'), +psa_api_tool_path = os.path.normpath(os.path.join(os.path.dirname(__file__), '..', '..', 'tools')) +psa_api_tool_path = os.environ.get('PSA_API_TOOL') or psa_api_tool_path +exec(compile(open(os.path.join(psa_api_tool_path,'psa-api-conf.py'), encoding='utf-8').read(), - 'atg-sphinx-conf.py', 'exec')) + 'psa-api-conf.py', 'exec')) diff --git a/doc/status-code/index.rst b/doc/status-code/index.rst index 0ac97848..60adba0b 100644 --- a/doc/status-code/index.rst +++ b/doc/status-code/index.rst @@ -3,17 +3,9 @@ .. title:: - .. abstract:: - - This document is part of the PSA Certified API specifications. It defines common interface elements relating to status and error codes. - -.. front-matter:: - - about/about - .. maintoc:: - overview/intro + about/about api/status-codes .. appendix:: diff --git a/doc/status-code/overview/intro.rst b/doc/status-code/overview/intro.rst deleted file mode 100644 index 82024e6a..00000000 --- a/doc/status-code/overview/intro.rst +++ /dev/null @@ -1,17 +0,0 @@ -.. SPDX-FileCopyrightText: Copyright 2022, 2025 Arm Limited and/or its affiliates -.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license - -Introduction -============ - -About Platform Security Architecture ------------------------------------- - -This document is one of a set of resources provided by Arm that can help organizations develop products that meet the security requirements of GlobalPlatform's PSA Certified evaluation scheme on Arm-based platforms. The PSA Certified scheme provides a framework and methodology that helps silicon manufacturers, system software providers and OEMs to develop more secure products. Arm resources that support PSA Certified range from threat models, standard architectures that simplify development and increase portability, and open-source partnerships that provide ready-to-use software. You can read more about PSA Certified here at :url:`www.psacertified.org` and find more Arm resources here at :url:`developer.arm.com/platform-security-resources` and :url:`www.trustedfirmware.org`. - -About the |API| ---------------- - -The interface described in this document is a PSA Certified API, that provides a shared set of interface definitions used by other PSA Certified APIs. - -You can find additional resources relating to the |API| here at :url:`arm-software.github.io/psa-api/status-code`, and find other PSA Certified APIs here at :url:`arm-software.github.io/psa-api`. diff --git a/doc/status-code/pyproject.toml b/doc/status-code/pyproject.toml new file mode 100644 index 00000000..52de3a0e --- /dev/null +++ b/doc/status-code/pyproject.toml @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: Copyright 2026 Arm Limited and/or its affiliates +# SPDX-License-Identifier: Apache-2.0 + +[tool.esbonio] diff --git a/doc/storage/about.rst b/doc/storage/about.rst deleted file mode 100644 index 2abc0bed..00000000 --- a/doc/storage/about.rst +++ /dev/null @@ -1,145 +0,0 @@ -.. SPDX-FileCopyrightText: Copyright 2018-2019, 2022-2025 Arm Limited and/or its affiliates -.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license - -.. Releases of this specification - -.. release:: 1.0 beta 2 - :date: Feb 2019 - :confidentiality: Non-confidential - - Initial publication. - -.. release:: 1.0.0 - :date: June 2019 - :confidentiality: Non-confidential - - First stable release with 1.0 API finalized. - - Uses the common PSA Certified Status codes. - - Modified the API parameters to align with other PSA Certified APIs. - - Added storage flags to specify protection requirement. - -.. release:: 1.0.1 - :date: October 2022 - :confidentiality: Non-confidential - - Relicensed as open source under CC BY-SA 4.0. - - Documentation clarifications. - -.. release:: 1.0.2 - :date: March 2023 - :confidentiality: Non-confidential - - Documentation clarifications. - -.. release:: 1.0.3 - :date: January 2024 - :confidentiality: Non-confidential - - Provide a Security Risk Assessment. - -.. release:: 1.0.4 - :date: September 2025 - :confidentiality: Non-confidential - - GlobalPlatform governance of PSA Certified evaluation scheme. - -.. release-info:: - :extend: - - The detailed changes in each release are described in :secref:`document-history`. - - -.. References used in this specification - -.. reference:: PSM - :title: Platform Security Model - :doc_no: ARM DEN 0128 - :url: developer.arm.com/documentation/den0128 - -.. reference:: PSA-CRYPT - :title: PSA Certified Crypto API - :doc_no: IHI 0086 - :url: arm-software.github.io/psa-api/crypto - -.. reference:: PSA-STAT - :title: PSA Certified Status code API - :doc_no: ARM IHI 0097 - :url: arm-software.github.io/psa-api/status-code - -.. reference:: PSA-FFM - :title: Arm® Platform Security Architecture Firmware Framework - :doc_no: ARM DEN 0063 - :url: developer.arm.com/documentation/den0063 - -.. reference:: SP800-30 - :title: NIST Special Publication 800-30 Revision 1: Guide for Conducting Risk Assessments - :author: NIST - :publication: September 2012 - :url: doi.org/10.6028/NIST.SP.800-30r1 - -.. Glossary terms used in this specification - -.. term:: Application Root of Trust - :abbr: ARoT - - This is the security domain in which additional security services are implemented. See :cite-title:`PSM`. - -.. scterm:: Implementation Defined - - Behavior that is not defined by the this specification, but is defined and documented by individual implementations. - - Firmware developers can choose to depend on :sc:`IMPLEMENTATION DEFINED` behavior, but must be aware that their code might not be portable to another implementation. - -.. term:: Non-secure Processing Environment - :abbr: NSPE - - This is the security domain outside of the :term:`Secure Processing Environment`. It is the Application domain, typically containing the application firmware and hardware. - -.. term:: Platform Root of Trust - :abbr: PRoT - - The overall trust anchor for the system. This ensures the platform is securely booted and configured, and establishes the secure environments required to protect security services. See :cite-title:`PSM`. - -.. term:: Root of Trust - :abbr: RoT - - This is the minimal set of software, hardware and data that is implicitly trusted in the platform --- there is no software or hardware at a deeper level that can verify that the Root of Trust is authentic and unmodified. - -.. term:: Root of Trust Service - :abbr: RoT Service - - A set of related security operations that are provided by a :term:`Root of Trust`. - -.. term:: Secure Partition - - A processing context with protected runtime state within the :term:`Secure Processing Environment`. A secure partition may implement one or more :term:`RoT Service`\s, accessible via well-defined interfaces. - -.. term:: Secure Processing Environment - :abbr: SPE - - This is the security domain that includes the :term:`Platform Root of Trust` and the :term:`Application Root of Trust` domains. - -.. term:: Secure Partition Manager - :abbr: SPM - - Part of the :term:`Secure Processing Environment` that is responsible for allocating resources to :term:`Secure Partition`\s, managing the isolation and execution of software within partitions, and providing IPC between partitions. - - -.. potential-for-change:: - - The contents of this specification are stable for version 1.0. - - The following may change in updates to the version 1.0 specification: - - * Small optional feature additions. - * Clarifications. - - Significant additions, or any changes that affect the compatibility of the - interfaces defined in this specification will only be included in a - new major or minor version of the specification. - -.. about:: diff --git a/doc/storage/about/about.rst b/doc/storage/about/about.rst new file mode 100644 index 00000000..58d67b48 --- /dev/null +++ b/doc/storage/about/about.rst @@ -0,0 +1,12 @@ +.. SPDX-FileCopyrightText: Copyright 2018-2019, 2022-2026 Arm Limited and/or its affiliates +.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +.. include:: intro + +.. include:: releases + +.. include:: references + +.. include:: terms + +.. about:: diff --git a/doc/storage/about/intro b/doc/storage/about/intro new file mode 100644 index 00000000..797c4723 --- /dev/null +++ b/doc/storage/about/intro @@ -0,0 +1,30 @@ +.. SPDX-FileCopyrightText: Copyright 2018-2019, 2022,2025 Arm Limited and/or its affiliates +.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +.. introduction:: + + This document is one of a set of resources that can help organizations develop products that meet the security requirements of GlobalPlatform's PSA Certified evaluation scheme. The PSA Certified scheme provides a framework and methodology that helps silicon manufacturers, system software providers and OEMs to develop more secure products. You can read more about PSA Certified here at :url:`www.psacertified.org`. + + .. rubric:: About the |API| + + The interface described in this document is a PSA Certified API, that provides key/value storage interfaces for use with device-protected storage. The |API| describes two interfaces for storage: + + .. csv-table:: + :widths: 3 7 + + Internal Trusted Storage API, An interface for storage provided by the :term:`Platform Root of Trust` (PRoT). + Protected Storage API, An interface for external protected storage. + + The Internal Trusted Storage API must be implemented in the PRoT as described in the :cite-title:`PSM` specification. + + If there are no :term:`Application Root of Trust` (ARoT) services that rely on it, the Protected Storage API can be implemented in the :term:`NSPE`. Otherwise, the Protected Storage API must be implemented in an ARoT within the :term:`SPE`. + + You can find additional resources relating to the |API| here at :url:`arm-software.github.io/psa-api/storage`, and find other PSA Certified APIs here at :url:`arm-software.github.io/psa-api`. + +.. audience:: + + This document is intended primarily for the use of developers of: + + * Root of Trust Services and security frameworks that implement the |API|. + * Root of Trust Services and Trusted Applications that use the |API| to access storage services. + * Client applications that use the |API| to access storage services. diff --git a/doc/storage/about/references b/doc/storage/about/references new file mode 100644 index 00000000..6f8f003b --- /dev/null +++ b/doc/storage/about/references @@ -0,0 +1,34 @@ +.. SPDX-FileCopyrightText: Copyright 2018-2019, 2022-2026 Arm Limited and/or its affiliates +.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +.. reference:: PSA STAT + :title: PSA Certified Status code API + :kind: normative + :doc_id: Arm IHI 0097 + :url: arm-software.github.io/psa-api/status-code + +.. reference:: PSA CRYPT + :title: PSA Certified Crypto API + :kind: informative + :doc_id: Arm IHI 0086 + :url: arm-software.github.io/psa-api/crypto + +.. reference:: PSM + :title: Platform Security Model + :kind: normative + :doc_id: JSADEN014 + :author: PSA Certified + :url: psacertified.org/development-resources/building-in-security/threat-models/ + +.. reference:: PSA FFM + :title: Arm® Platform Security Architecture Firmware Framework + :kind: normative + :doc_id: Arm DEN 0063 + :url: developer.arm.com/documentation/den0063 + +.. reference:: SP800-30 + :title: Special Publication 800-30 Revision 1: Guide for Conducting Risk Assessments + :kind: informative + :author: NIST + :publication: September 2012 + :url: doi.org/10.6028/NIST.SP.800-30r1 diff --git a/doc/storage/about/releases b/doc/storage/about/releases new file mode 100644 index 00000000..9a07dc92 --- /dev/null +++ b/doc/storage/about/releases @@ -0,0 +1,45 @@ +.. SPDX-FileCopyrightText: Copyright 2018-2019, 2022-2026 Arm Limited and/or its affiliates +.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +.. release:: 1.0.0 + :date: June 2019 + :confidentiality: Non-confidential + + First stable release with 1.0 API finalized. + + Uses the common PSA Certified Status codes. + + Modified the API parameters to align with other PSA Certified APIs. + + Added storage flags to specify protection requirement. + +.. release:: 1.0.1 + :date: October 2022 + :confidentiality: Non-confidential + + Relicensed as open source under CC BY-SA 4.0. + + Documentation clarifications. + +.. release:: 1.0.2 + :date: March 2023 + :confidentiality: Non-confidential + + Documentation clarifications. + +.. release:: 1.0.3 + :date: January 2024 + :confidentiality: Non-confidential + + Provide a Security Risk Assessment. + +.. release:: 1.0.4 + :date: September 2025 + :confidentiality: Non-confidential + + GlobalPlatform governance of PSA Certified evaluation scheme. + +.. release-info:: + :extend: + + The detailed changes in each release are described in :secref:`document-history`. diff --git a/doc/storage/about/terms b/doc/storage/about/terms new file mode 100644 index 00000000..967ccfb3 --- /dev/null +++ b/doc/storage/about/terms @@ -0,0 +1,47 @@ +.. SPDX-FileCopyrightText: Copyright 2018-2019, 2022-2025 Arm Limited and/or its affiliates +.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +.. term:: Application Root of Trust + :abbr: ARoT + + This is the security domain in which additional security services are implemented. See :cite-title:`PSM`. + +.. scterm:: Implementation Defined + + Behavior that is not defined by the this specification, but is defined and documented by individual implementations. + + Firmware developers can choose to depend on :sc:`IMPLEMENTATION DEFINED` behavior, but must be aware that their code might not be portable to another implementation. + +.. term:: Non-secure Processing Environment + :abbr: NSPE + + This is the security domain outside of the :term:`Secure Processing Environment`. It is the Application domain, typically containing the application firmware and hardware. + +.. term:: Platform Root of Trust + :abbr: PRoT + + The overall trust anchor for the system. This ensures the platform is securely booted and configured, and establishes the secure environments required to protect security services. See :cite-title:`PSM`. + +.. term:: Root of Trust + :abbr: RoT + + This is the minimal set of software, hardware and data that is implicitly trusted in the platform --- there is no software or hardware at a deeper level that can verify that the Root of Trust is authentic and unmodified. + +.. term:: Root of Trust Service + :abbr: RoT Service + + A set of related security operations that are provided by a :term:`Root of Trust`. + +.. term:: Secure Partition + + A processing context with protected runtime state within the :term:`Secure Processing Environment`. A secure partition may implement one or more :term:`RoT Service`\s, accessible via well-defined interfaces. + +.. term:: Secure Processing Environment + :abbr: SPE + + This is the security domain that includes the :term:`Platform Root of Trust` and the :term:`Application Root of Trust` domains. + +.. term:: Secure Partition Manager + :abbr: SPM + + Part of the :term:`Secure Processing Environment` that is responsible for allocating resources to :term:`Secure Partition`\s, managing the isolation and execution of software within partitions, and providing IPC between partitions. diff --git a/doc/storage/api/api.rst b/doc/storage/api/api.rst index 9093306b..c64873c5 100644 --- a/doc/storage/api/api.rst +++ b/doc/storage/api/api.rst @@ -9,7 +9,7 @@ Status codes The |API| uses the status code definitions that are shared with the other PSA Certified APIs. -The following elements are defined in :file:`psa/error.h` from :cite-title:`PSA-STAT` (previously defined in :cite:`PSA-FFM`): +The following elements are defined in :file:`psa/error.h` from :cite-title:`PSA STAT`: .. code-block:: xref diff --git a/doc/storage/appendix/history.rst b/doc/storage/appendix/history.rst index 5a0108be..c61b6c14 100644 --- a/doc/storage/appendix/history.rst +++ b/doc/storage/appendix/history.rst @@ -15,13 +15,19 @@ Document history - Release - Details + * - TBD + - *Draft GlobalPlatform publication revision* + - Migrated the document to the 2026 PSA Certified API template. + + This changes the document front matter structure and publication styling, without changing the API. + * - 2019-02-25 - *1.0 Beta 2* - First Release * - 2019-06-12 - *1.0 Rel* - - Final 1.0 API + - 1.0 API finalized The protected storage API now supports flags `PSA_STORAGE_FLAG_NO_CONFIDENTIALITY` and `PSA_STORAGE_FLAG_NO_REPLAY_PROTECTION`. diff --git a/doc/storage/appendix/sra.rst b/doc/storage/appendix/sra.rst index 44586caa..5342af1f 100644 --- a/doc/storage/appendix/sra.rst +++ b/doc/storage/appendix/sra.rst @@ -1,1220 +1,1220 @@ .. SPDX-FileCopyrightText: Copyright 2023-2024 Arm Limited and/or its affiliates -.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license - -.. _sra: - -Security Risk Assessment -======================== - -This appendix provides a Security Risk Assessment (SRA) of the |API| and of a generic implementation of storage. -It describes the threats presented by various types of adversaries against the security goals for an implementation of a secure storage service, and mitigating actions for those threats. - -* :secref:`sra-about` describes the assessment methodology. -* :secref:`sra-definition` defines the security problem. -* :secref:`sra-threats` describes the threats and the recommended mitigating actions. -* :secref:`sra-mitigations` summarizes the mitigations, and where these are implemented. - -.. _sra-about: - -About this assessment ---------------------- - -Subject and scope -^^^^^^^^^^^^^^^^^ - -This SRA analyses the security of the |API| itself, and of the conceptual architectures for storage, not of any specific implementation of the API, or any specific use of the API. -It does, however, divide implementations into four deployment models representing common implementation types, and looks at the different mitigations needed in each deployment model. - -In this SRA: - -* *Storage service* means the firmware implementing the |API|. -* *Storage medium* refers to the physical storage location. - -Risk assessment methodology -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Our risk ratings use an approach derived from :cite-title:`SP800-30`: for each Threat, we determine its Likelihood and the Impact. -Each is evaluated on a 5-level scale, as defined in :numref:`tab-sra-likelihood` and :numref:`tab-sra-impact`. - -.. list-table:: Likelihood levels - :name: tab-sra-likelihood - :header-rows: 1 - :stub-columns: 1 - :widths: 1 6 - - * - Level - - Definition - - * - Very Low - - Unlikely to ever occur in practice, or *mathematically near impossible* - * - Low - - The event could occur, but only if the attacker employs *significant* resources; or it is *mathematically unlikely* - * - Medium - - A motivated, and well-equipped adversary can make it happen within the lifetime of a product based on the feature (resp. of the feature itself) - * - High - - Likely to happen within the lifetime of the product or feature - * - Very High - - Will happen, and soon (for instance a zero-day) - -.. list-table:: Impact levels - :name: tab-sra-impact - :header-rows: 1 - :stub-columns: 1 - :widths: 1 3 3 - - * - Level - - Definition - - Example Effects - - * - Very Low - - Causes virtually no damage. - - Probably none. - * - Low - - The damage can easily be tolerated or absorbed. - - There would be a CVE at most. - * - Medium - - The damage will have a *noticeable* effect, such as *degrading* some functionality, but won't degrade completely the use of the considered functionality. - - There would be a CVE at most. - * - High - - The damage will have a *strong* effect, such as causing a significant reduction in its functionality or in its security guarantees. - - Security Analysts would discuss this at length, there would be papers, blog entries. - Partners would complain. - * - Very High - - The damage will have *critical* consequences --- it could kill the feature, by affecting several of its security guarantees. - - It would be quite an event. - - Partners would complain strongly, and delay or cancel deployment of the feature. - -For both Likelihood and Impact, when in doubt always choose the higher value. -These two values are combined using :numref:`tab-sra-overall-risk` to determine the Overall Risk of a Threat. - -.. csv-table:: Overall risk calculation - :name: tab-sra-overall-risk - :header-rows: 2 - :stub-columns: 1 - :align: right - - ,Impact,,,, - Likelihood, Very Low, Low, Medium, High, Very High - Very Low, Very Low, Very Low, Very Low, Low, Low - Low, Very Low, Very Low, Low, Low, Medium - Medium, Very Low, Low, Medium, Medium, High - High, (Very) Low, Low, Medium, High, Very High - Very High, (Very) Low, Medium, High, Very High, Very High - -Threats are handled starting from the most severe ones. -Mitigations will be devised for these Threats one by one (note that a Mitigation may mitigate more Threats, and one Threat may require the deployment of more than one Mitigation to be addressed). -Likelihood and Impact will be reassessed assuming that the Mitigations are in place, resulting in a Mitigated Likelihood (this is the value that usually decreases), a Mitigated Impact (it is less common that this value will decrease), and finally a Mitigated Risk. -The Analysis is completed when all the Mitigated Risks are at the chosen residual level or lower, which usually is Low or Very Low. - -The Mitigating actions that can be taken are defined in the acronym **CAST**: - -* **Control**: Put in place steps to reduce the Likelihood and/or Impact of a Threat, thereby reducing the risk to an acceptable level. -* **Accept**: The threat is considered to be of acceptable risk such that a mitigation is not necessary or must be accepted because of other constraint or market needs. -* **Suppress**: Remove the feature or process that gives rise to the threat. -* **Transfer**: Identify a more capable or suitable party to address the risk and transfer the responsibility of providing a mitigation for the threat to them. - -.. _sra-definition: - -Feature definition ------------------- - -Introduction -^^^^^^^^^^^^ - -Background -~~~~~~~~~~ - -:secref:`intro` provides the context in which the |API| is designed. - -Purpose -~~~~~~~ - -The |API| separates the software responsible for providing the security of the data from the caller. -The storage service calls on firmware that provides low level reads and writes of non-volatile storage medium and the access to any required bus. -The |API| is to provide a consistent interface, so that applications do not need to account for the different low-level implementations. - -This analysis does not address the engineering requirements to create a reliable storage medium from the underlying physical storage. -It is assumed that the implementation will use the standard techniques, error correcting codes, wear levelling and so on, to ensure the storage is reliable. - -Lifecycle -^^^^^^^^^ - -:numref:`fig-lifecycle` shows the typical lifecycle of a device. - -.. figure:: /figure/lifecycle.* - :name: fig-lifecycle - - Device lifecycle of a system providing storage - -The storage service, and the |API| are active during the operational phase, implemented within the boot-time and run-time software. - -Within a boot session, it is the responsibility of the secure boot firmware to: - -* Set up the isolation barriers between partitions. -* Provision the firmware implementing the storage service. -* Provision the credentials for authorizing the storage of data. -* Enable or disable debug facilities. - -This SRA only considers threats to the storage service in its operational phase. -The security of the boot process and of any data provisioning service are not considered in this SRA. - -Operation and trust boundaries -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:numref:`fig-boundaries` shows all of the main components in the storage service. -Presenting the context in which the |API| operates aids understanding of the threats and security mitigations and provides justification for some of the aspects of the API design. - -.. figure:: /figure/callers.* - :name: fig-boundaries - - Trust boundaries of a system providing storage - -|API| is a C language API. -Therefore, any implementation of the API must execute, at least partially, within the context of the caller. -When an implementation includes a trust boundary, the mechanism and protocol for communication across the boundary is not defined by this specification. - -The operational dataflow diagram is reproduced for each of the deployment models. -Although the dataflow itself is common to the models, the placement of trust boundaries is different. - -It is helpful to visualize the effect of these differences on the threats against the dataflows. - - -Deployment models -^^^^^^^^^^^^^^^^^ - -:deployment-model:`PROTECTED` - The storage service and all physical storage is within the :term:`Platform Root of Trust` (:term:`PRoT`) partition. - The :term:`PRoT` partition has sole access to an area of non-volatile storage, thus that storage cannot be accessed by any other partition or any other means. - This means that the storage service, any driver code, the storage service and storage medium all reside with the :term:`PRoT` and are protected by the :term:`PRoT`'s isolation mechanisms as shown in :numref:`fig-protected`. - - .. figure:: /figure/dm-protected.* - :name: fig-protected - - Trust boundaries in the deployment model `DM.PROTECTED` - - The storage service is the arbitrator of access from different applications and manages all data accesses (write, update and deletion). - Therefore, the storage service is responsible for the `SG.CONFIDENTIALITY`, `SG.INTEGRITY` and `SG.CURRENCY` goals of each caller, including maintaining confidentiality between different callers. - - An example of this deployment model is the use of on-chip flash or OTP with an access control mechanism such as a Memory Protection Unit. - -:deployment-model:`EXPOSED` - The :term:`PRoT` partition does not have sole access to the area of non-volatile storage, thus the storage medium can be read or written by another partition or by other means. - This means that the driver code, or the storage medium resides outside the :term:`PRoT` and is accessible to other partitions or by other means, as shown in as shown in :numref:`fig-exposed`. - Therefore, attackers can bypass the storage service. - - .. figure:: /figure/dm-exposed.* - :name: fig-exposed - - Trust boundaries in the deployment model `DM.EXPOSED` - - The storage service is the arbitrator of access from different applications and manages accesses that write, update, and delete data. - Therefore, the storage service is responsible for the `SG.CONFIDENTIALITY`, `SG.INTEGRITY` and `SG.CURRENCY` goal with respect to preventing access by a different caller. - - The storage service cannot prevent other partitions or other means from reading or writing the storage, or accessing the link DF3. - Therefore, the storage service is responsible for the `SG.CONFIDENTIALITY`, `SG.INTEGRITY` and `SG.CURRENCY` goals. - - An example of this deployment model is the use of a file system on a flash chip. - - -:deployment-model:`AUTHORIZED` - There is a separate isolated storage medium that can only be accessed in response to an authenticated command and from which all replies include a means for verification of the response, as shown in :numref:`fig-authorized`. - The isolation guarantees that there is no access to the storage medium other than by using the authentication mechanism. - - .. figure:: /figure/dm-authorized.* - :name: fig-authorized - - Trust boundaries in the deployment model `DM.AUTHORIZED` - - The storage service is the arbitrator of access from different applications and manages those data accesses (write, update and deletion). - Therefore, the storage service is responsible for the `SG.CONFIDENTIALITY` goal with respect to preventing access by a different caller. - - The authorization and verification mechanism provided by the storage medium controls access to data (reads, writes and modification). - Therefore, the storage medium is responsible for the `SG.INTEGRITY` and `SG.CURRENCY` goals. - Attacks on these mechanisms are out of scope. - - However, the communication between the storage service and the storage medium is observable by other partitions and any other means as any data sent in plain text can be observed. - Therefore, the storage service is responsible for `SG.CONFIDENTIALITY`. - - The storage service and the storage medium are jointly responsible for protecting the assets required to authorize commands. - Attacks on the storage service that expose these assets are in scope. - - An example of this deployment model is the use of an RPMB memory block. - -:deployment-model:`SECURE_LINK` - There is a separate isolated storage medium that can only be accessed across a cryptographically protected secure channel as shown in :numref:`fig-external-secure`. - The secure channel protocol provides authentication, confidentiality and integrity of data in transit. - The isolation guarantees that there is no access to the storage medium other than by using this channel. - - .. figure:: /figure/dm-secure-link.* - :name: fig-external-secure - - Trust boundaries in the deployment model `DM.SECURE_LINK` - - The storage service is the arbitrator of access from different applications and manages those data accesses (write, update and deletion). - Therefore, the storage service is responsible for the `SG.CONFIDENTIALITY` goal with respect to preventing access by a different caller. - - The authorization and verification mechanism provided by the secure channel protocol controls access to data (reads, writes and modification). - Therefore, the storage medium is responsible for the `SG.INTEGRITY` and `SG.CURRENCY` goals. - Attacks on the storage medium are out of scope. - - The communication between the storage service and the storage medium is protected from observation by other partitions and other means as the data is sent in encrypted form over the secure channel. - Attacks on the secure channel protocol are out of scope. - - The storage service uses the secure channel protocol, the storage service and the storage medium are jointly responsible for protecting the assets required to set up the channel. - Attacks on the storage service that expose these assets are in scope. - - An example of this deployment model is the use of a Secure Element, or a secure flash device. - - -.. _isolation: - -Optional isolation -~~~~~~~~~~~~~~~~~~ - -Implementations can isolate the storage service from the caller and can further isolate multiple calling applications. -Various technologies can provide protection, for example: - -* Process isolation in an operating system. -* Partition isolation, either with a virtual machine or a partition manager. -* Physical separation between execution environments. - -The mechanism for identifying callers is beyond the scope of this specification. -An implementation that provides caller isolation must document the identification mechanism. -An implementation that provides caller isolation must document any implementation-specific extension of the API that enables callers to share data in any form. - -In summary, there are three types of implementation: - -* No isolation: there is no security boundary between the caller and the storage service. - For example, a statically or dynamically linked library is an implementation with no isolation. - As the caller is in the same security domain as the storage, the API cannot prevent access to the storage medium that does not go through the API. - -* Simple Isolation: A single security boundary separates the storage service from the callers, but there is no isolation between callers. - The only access to stored data is via the storage service, but the storage service cannot partition data between different callers. - -* Caller isolation: there are multiple caller instances, with a security boundary between the caller instances among themselves, as well as between the storage service and the caller instances. - For example, a storage service in a multiprocessor environment is an implementation with caller isolation. - The only access to the stored data is via the storage service and the storage service can partition stored data between the different callers. - -Assumptions, constraints, and interacting entities -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -This SRA makes the following assumptions about the |API| design: - -* The API does not provide arguments that identify the caller, because they can be spoofed easily, and cannot be relied upon. - It is assumed that the implementation of the API can determine the caller identity, where this is required. - See :secref:`isolation`. - -* The API does not prevent the use of mitigations that are required by an implementation of the API. - See :secref:`tab-sra-remediations`. - -* The :cite-title:`PSM` assumes that at least the code in the :term:`Root of Trust` partitions (:term:`PRoT` and :term:`ARoT`) are verified at boot, and on any update. - Therefore, it is assumed that this code is trustworthy. - If any malicious code can run in the RoT partitions, it has achieved full control. - -* For the purposes of this analysis, it is assumed that in deployment models `DM.AUTHORIZED` and `DM.SECURE_LINK`, there is no way to access the stored data without going through the authenticated channel. - That is, an attack that would expose the physical storage medium is beyond the resources of the attacker. - -* The analysis ignores attacks that only result in a denial of service. - There are many ways an attacker can deny service to the complete system, with or without involving the storage service. - -* The analysis only looks at an active attack. - However, data is also subject to accidental modification, for example from cosmic radiation causing a bit flip. - Therefore, standard engineering practice --- such as use of error correcting codes --- should be taken to protect data. - -Stakeholders and Assets -^^^^^^^^^^^^^^^^^^^^^^^ - -This analysis looks at the security from the point of view of the applications that call on the service to store data, and on the overall system. - -The following assets are considered in this assessment: - -Data to be stored - The purpose of a storage service is to securely store data for its callers. - -Caller Identities - To ensure that data stored for one caller is not revealed to a different caller, each caller must have a unique identity. - -Implementation Secrets - If in order to secure the data, the storage service uses encryption keys for confidentiality and integrity, these mut be considered assets of the storage service. - -Goals -^^^^^ - -:security-goal:`CONFIDENTIALITY` - An adversary is unable to disclose Stored Data that belongs to a different Stored Data Owner. - A legitimate owner can guarantee their data has not been exposed. - -:security-goal:`INTEGRITY` - An adversary is unable to modify Stored Data that belongs to a different Stored Data Owner, to a value that was not previously stored by the Stored Data Owner. - A legitimate owner can guarantee that data returned is a value they have stored. - -:security-goal:`CURRENCY` - An adversary is unable to modify Stored Data that belongs to a different Stored Data Owner. - The legitimate owner can guarantee that data returned is the most recent value that have stored. - -Adversarial models -^^^^^^^^^^^^^^^^^^ - -Adversarial models are descriptions of capabilities that adversaries of systems implementing the |API| can have, grouped into classes. -The adversaries are defined in this way to assist with threat modelling an abstract API, which can have different implementations, in systems with a wide range of security sensitivity. - -:adversarial-model:`0` - The Adversary is only capable of accessing data that requires neither physical access to a system containing an implementation of the feature nor the ability to run software on it. - This Adversary is intercepting or providing data or requests to the target system via a network or other remote connection. - - For instance, the Adversary can: - - * Read any input and output to the target through external apparatus. - * Provide, forge, replay or modify such inputs and outputs. - * Perform timings on the observable operations being done by the target, either in normal operation or as a response to crafted inputs. - For example, timing attacks on web servers. - -:adversarial-model:`1` - The Adversary can additionally mount attacks from software running on a target processor implementing the feature. - This type of Adversary can run software on the target. - - For instance, the Adversary can: - - * Attempt software exploitation by running software on the target. - * Exploit access to any memory mapped configuration, monitoring, debug register. - * Mount any side channel analysis that relying on software-exposed built-in hardware features to perform physical unit and time measurements. - * Perform software-induced glitching of resources such as Rowhammer, RASpberry or crashing the CPU by running intensive tasks. - -:adversarial-model:`2` - In addition to the above, the Adversary is capable of mounting hardware attacks and fault injection that does not require breaching the physical envelope of the chips. - This type of Adversary has access to a system containing an implementation of the target feature. - - For instance, the Adversary can: - - * Conduct side-channel analysis that requires measurement equipment. - For example, this can utilize leakage sources such as EM emissions, power consumption, photonics emission, or acoustic channels. - * Plug malicious hardware into an unmodified system. - * Gain access to the internals of the target system and interpose the SoC or memory for the purposes of reading, blocking, replaying, and injecting transactions. - * Replace or add chips on the motherboard. - * Make simple, reversible modifications, to perform glitching. - -:adversarial-model:`3` - In addition to all the above, the Adversary can perform invasive SoC attacks. - - For instance, the Adversary can: - - * Decapsulate a chip, via laser or chemical etching, followed by microphotography to reverse engineer the chip. - * Use a focused ion beam microscope to perform gate level modification. - -The adversarial models that are in scope depend on the product requirements. -To ensure that the |API| can be used in a wide range of systems, this assessment considers adversarial models `AM.0`, `AM.1`, and `AM.2` to be in-scope. - -Code in the RoT partitions is assumed to be trustworthy --- and any untrustworthy code running in :term:`PRoT` partitions already has complete control of the target --- therefore, in `AM.1` this SRA only considers threats from malicious actors running in :term:`Non-secure Processing Environment`. - -.. _sra-threats: - -Threats -------- - -Because |API| can be used in a wide range of deployment models and a wide range of threats, not all mitigating actions apply to all deployment models. -As a result, various mitigations are optional to implement, depending on which threats exist in a particular domain of application, and which deployment model is used. - -:numref:`tab-sra-threats` summarizes the threats. - -.. csv-table:: Summary of threats - :name: tab-sra-threats - :class: longtable - :align: left - :widths: 1 3 - :header-rows: 1 - - Threat, Description - `T.INTERFACE_ABUSE`, Call the API with illegal inputs - `T.SPOOF_READ`, Reading data for a different caller using the API - `T.SPOOF_WRITE`, Writing data for a different caller using the API - `T.EAVESDROPPING`, Accessing data in transit - `T.MITM`, A Man in the Middle can actively interfere with communication - `T.DIRECT_READ`, "Directly reading stored data, bypassing the API" - `T.DIRECT_WRITE`, "Directly modifying data, bypassing the API" - `T.REPLACE`, Physical replacement of the storage medium - `T.GLITCH_READ`, Glitching during a read - `T.GLITCH_WRITE`, Glitching during a write - -.. threat:: Illegal inputs to the API - :id: INTERFACE_ABUSE - - .. description:: - An attacker can abuse the |API|. - For example: - - * Passing out of range values to the interface to provoke unexpected behavior of the implementation. - * Passing invalid input or output buffers to the interface, that would cause the implementation to access non-existent memory, or memory that is inaccessible to the caller --- including accessing assets of the storage service. - - .. security-goal:: `SG.CONFIDENTIALITY`, `SG.INTEGRITY` - .. adversarial-model:: `AM.1` - - .. mitigations:: - :mitigation:`ValidateParameter`. - **Transfer** to the implementation: check all API parameters to lie within valid ranges, including memory access permissions. - - :mitigation:`MemoryBuffer`. - **Control** by API design: input buffers are fully consumed by the implementation before returning from a function. - An implementation must not access the caller's memory after a function has returned. - - .. unmitigated:: - :impact: VH - :likelihood: VH - - .. residual:: - :impact: VH - :likelihood: VL - - -.. threat:: Use the API to read another caller's data - :id: SPOOF_READ - - .. description:: - In all deployment models, an attacker attempts to read data stored for another caller using the |API|. - - The API does not require that the names used by caller for stored data are globally unique, only unique within that caller's namespace. - - .. mitigations:: - :mitigation:`ImplicitIdentity`. - **Control** by API design: caller identity is not provided by the caller to the API. - If caller identity is supplied by the caller in the API, the identity can be spoofed by another caller. - Using authentication credentials only moves the problem of storing secrets, but does not solve it. - - **Transfer** to the implementation: provide caller identities, to isolate data that belongs to different callers. - The assurance that the storage service can give is limited by the assurance that the implementation can give as to the identity of the caller. - - Where each user runs in a separate partition, the identity can be provided by the partition manager. - Where different users run within a single partition, **Transfer** the responsibility for separating users within that partition to the operating system or run time within that partition. - - :mitigation:`FullyQualifiedNames`. - **Transfer** to the implementation: use a fully-qualified data identifier, that is a combination of an owner identity and the item UID. - The implementation must used the owner identity to ensure that a data request to the storage service does not return data of the same UID, that was stored by a different caller. - - The storage service must also ensure that if a data item with the fully-qualified identifier does not exist, the implementation returns the correct error. - - .. security-goal:: :SG:`CONFIDENTIALITY` - - .. adversarial-model:: `AM.1` - - .. unmitigated:: - :impact: VH - :likelihood: VH - - .. residual:: - :impact: VH - :likelihood: VL - -.. threat:: Use the API to modify another caller's data - :id: SPOOF_WRITE - - .. description:: - In all deployment models, an attacker attempts to write data to a file belonging to another caller using the |API| or create a new file in a different caller's namespace. - - This threat is the counterpart to `T.SPOOF_READ` except that the attacker tries to write data rather than read. - It is therefore subject to the same analysis. - - .. mitigations:: `M.FullyQualifiedNames`, `M.ImplicitIdentity`. - - .. security-goal:: :SG:`CONFIDENTIALITY` - .. adversarial-model:: `AM.1` - - .. unmitigated:: - :impact: VH - :likelihood: VH - - .. residual:: - :impact: VH - :likelihood: VL - -.. threat:: Eavesdropping - :id: EAVESDROPPING - - .. description:: - An attacker accesses data in transit, either between the caller and the storage service, or between the storage service and the storage medium. - - In all deployment models, by the definition of an isolated partition in the :cite-title:`PSM`, transfer within the partition, and transfers between one :term:`Secure Partition` and another are isolated from eavesdroppers. - Therefore, if the caller is in a :term:`Secure Partition`, there is no possibility of an eavesdropper accessing the data. - However, if data is sent or returned to a caller in the :term:`Non-secure Processing Environment` (NSPE), although the data is securely delivered to the :term:`NSPE`, it is exposed to all users in the :term:`NSPE`. - As previously noted, the implementation **transfers** the duty of separating users in the :term:`NSPE` to the OS. - - For deployment model `DM.PROTECTED`, the storage service and the storage medium are isolated. - - In `DM.EXPOSED`, any adversary that can obtain operating system privileges in the :term:`NSPE` will have access to all the memory and will therefore be able to eavesdrop on all data in transit. - - An attacker that is external to the processor, `AM.2`, will be able to exploit an eavesdropping attack if the bus to which the memory is attached is accessible via external pins. - Otherwise, the attack is limited to internal attackers `AM.1`. - - In `DM.AUTHORIZED`, an attacker with access to the bus, or to intermediate data buffers, can eavesdrop and obtain the messages. - - In `DM.SECURE_LINK`, an attacker can only eavesdrop on any data transfer not protected by the secure channel. - - .. mitigations:: - :mitigation:`Encrypt`. - **Transfer** to the implementation: for `DM.EXPOSED` and `DM.AUTHORIZED`, the data at rest must be encrypted. - The storage service must apply the encryption to the data before it leaves the :term:`PRoT` partition. - The encryption mechanism chosen must be sufficiently robust. - The key used for encryption must be sufficiently protected, that is, it must only be available to the storage service. - - :mitigation:`PRoTRootedSecLink`. - **Transfer** to the implementation: for `DM.SECURE_LINK`, communication with the storage medium must be over a well-designed secure channel. - If the secure channel is not rooted in the :term:`PRoT` then any adversary in the partition (`AM.1`), or with access to the partition (`AM.2`), in which the channel terminates will be able to eavesdrop on traffic leaving the :term:`PRoT` before it is encrypted. - The secure channel must be rooted within the PRoT. - However, the stored data does not need to be separately encrypted beyond the protection provided by the secure channel. - The private information required to establish the channel must be suitably protected by both the storage service and the storage medium. - - :mitigation:`UseSecurePartitions`. - **Transfer** to the application: for all deployment models, place callers that handle sensitive data into separate partitions. - To ensure that an attacker in the :term:`NSPE` cannot access the data sent by the caller to the storage service, or the replies the storage service returns to the caller, place all code that needs to use the storage service into one or more :term:`Secure Partition`, with one partition per service. - - - .. security-goal:: :SG:`CONFIDENTIALITY` - - .. adversarial-model:: `AM.0`, `AM.1`, `AM.2` - - .. unmitigated:: DM.PROTECTED - :impact: VH - :likelihood: n/a --- except for transfer of data to clients in the :term:`NSPE` - :risk: n/a - - .. residual:: DM.PROTECTED - :impact: VH - :likelihood: n/a - :risk: n/a - - .. unmitigated:: DM.EXPOSED - :impact: VH - :likelihood: VH - - .. residual:: DM.EXPOSED - :impact: VH - :likelihood: VL - - .. unmitigated:: DM.AUTHORIZED - :impact: VH - :likelihood: H - - .. residual:: DM.AUTHORIZED - :impact: VH - :likelihood: VL - - .. unmitigated:: DM.SECURE_LINK - :impact: VH - :likelihood: H - - .. residual:: DM.SECURE_LINK - :impact: VH - :likelihood: VL - - -.. threat:: Man In The Middle - :id: MITM - - .. description:: - An attacker can actively interfere with communication and replace the transmitted data. - In this threat the SRA only considers attackers between the storage service and the storage medium. - An attacker interposing between the Caller and the storage service is considered under `T.SPOOF_READ` or `T.SPOOF_WRITE`. - - For `DM.PROTECTED`, the storage service and the storage medium are isolated. - - For `DM.EXPOSED`, any code running in the :term:`NSPE` has access to the storage medium and any driver firmware, and therefore can act as a man in the middle, by for example persuading the storage service to write to one buffer, and the storage medium to read from another. - - For `DM.AUTHORIZED`, a man in the middle eavesdrops on data in transit. - - For `DM.SECURE_LINK`, a naive secure channel is vulnerable to a man in the middle attack. - - .. mitigations:: - `M.Encrypt`. - **Transfer** to the implementation: if data is encrypted, a man in the middle cannot know what data is being transferred. - It also means they cannot force a specific value to be stored. - - :mitigation:`MAC`. - **Transfer** to the implementation: for `DM.EXPOSED`, apply a Message Authentication Code or a signature to the stored data, or use an authenticated encryption scheme. If the storage service checks the MAC or tag when data is read back from the storage medium to detect unauthorized modification. - - :mitigation:`UniqueKeys`. - **Transfer** to the implementation: for `DM.AUTHORIZED` and `DM.SECURE_LINK`, use unique keys for securing the authenticated or secure channel. - If the keys used by the storage medium are unique to each instance, as an attacker can only learn the key used on this specific instance. - They cannot construct a class break by discovering the key for every instance. - - :mitigation:`VerifyReplies`. - **Transfer** to the implementation: for `DM.AUTHORIZED`, commands and replies are authenticated by the storage medium. - Therefore, the man in the middle cannot forge a valid reply which indicates that the data has been stored when it has not. - If the storage service validates replies from the storage medium, it can verify that the data it sent was correctly stored, and the data retrieved is the value previously stored. - - :mitigation:`AuthenticateEndpoints`. - **Transfer** to the implementation: for `DM.SECURE_LINK`, use mutual authentication of the storage service and storage medium when setting up the secure channel. - For example, this can be achieved by using a single key, known only to both parties. - - :mitigation:`ReplayProtection`. - **Transfer** to the implementation: for `DM.AUTHORIZED` and `DM.SECURE_LINK`, use replay protection in the communication protocol. - This can be achieved by including a nonce in the construction of protocol messages. - This enables the storage medium to detect attempts to replay previous commands and reject them. - - .. security-goal:: :SG:`INTEGRITY` - .. adversarial-model:: `AM.1`, `AM.2` - - .. unmitigated:: DM.PROTECTED - :impact: VH - :likelihood: n/a - :risk: n/a - - .. residual:: DM.PROTECTED - :impact: VH - :likelihood: n/a - :risk: n/a - - .. unmitigated:: DM.EXPOSED - :impact: VH - :likelihood: VH - - .. residual:: DM.EXPOSED - :impact: VH - :likelihood: VL - - .. unmitigated:: DM.AUTHORIZED - :impact: VH - :likelihood: H - - .. residual:: DM.AUTHORIZED - :impact: H - :likelihood: VL - - .. unmitigated:: DM.SECURE_LINK - :impact: H - :likelihood: H - - .. residual:: DM.SECURE_LINK - :impact: H - :likelihood: VL - - -.. threat:: Bypassing the API to directly read data - :id: DIRECT_READ - - .. description:: - An attacker might be able to read stored data through a mechanism other than the API. - - In `DM.PROTECTED`, no attacker should be able to access the stored data. - - In `DM.EXPOSED`, all attackers can access the data. - - In `DM.AUTHORIZED`, the attacker cannot form valid requests to access data. - It can, however, eavesdrop on a legitimate request and replay it later. - - In `DM.SECURE_LINK`, the attacker cannot form valid requests to access data. - It can, however, eavesdrop on a legitimate request and even if it cannot understand it, it could replay it later. - - .. adversarial-model:: `AM.1`, `AM.2` - - .. security-goal:: :SG:`CONFIDENTIALITY` - - .. mitigations:: - `M.ReplayProtection`. - **Transfer** to the implementation: for `DM.AUTHORIZED` and `DM.SECURE_LINK`, use replay protection in the communication protocol. - - `M.Encrypt`. - **Transfer** to the implementation: for `DM.EXPOSED` and `DM.AUTHORIZED`, encrypting the data prevents disclosure. - - .. unmitigated:: DM.PROTECTED - :impact: VH - :likelihood: n/a - :risk: n/a - - .. residual:: DM.PROTECTED - :impact: VH - :likelihood: n/a - :risk: n/a - - .. unmitigated:: DM.EXPOSED - :impact: VH - :likelihood: VH - - .. residual:: DM.EXPOSED - :impact: VH - :likelihood: VL - - .. unmitigated:: DM.AUTHORIZED - :impact: VH - :likelihood: H - - .. residual:: DM.AUTHORIZED - :impact: H - :likelihood: VL - - .. unmitigated:: DM.SECURE_LINK - :impact: H - :likelihood: H - - .. residual:: DM.SECURE_LINK - :impact: H - :likelihood: VL - - - -.. threat:: Bypassing the API to directly modify data - :id: DIRECT_WRITE - - .. description:: An attacker might be able to modify data stored for another caller. - - In `DM.PROTECTED`, no attacker should be able to access the stored data. - - In `DM.EXPOSED`, the SRA assumes that any attacker capable of running code in the :term:`NSPE` can modify the stored data. - However, assuming it is encrypted, the attacker cannot create the correct ciphertext for chosen plain text. - - In `DM.AUTHORIZED`, although the attacker cannot form a valid command, the attacker can eavesdrop on a legitimate request and replay it later. - - In `DM.SECURE_LINK`, although the attacker cannot form a valid command, the attacker can eavesdrop on a legitimate request and replay it later. - - - .. adversarial-model:: `AM.1` `AM.2` - - .. security-goal:: `SG.INTEGRITY`, `SG.CURRENCY` - - .. mitigations:: - `M.Encrypt`. - **Transfer** to the implementation: encrypted data cannot be modified to an attacker-chosen plaintext value. - However, an attacker can still corrupt the stored data. - - `M.MAC`. - **Transfer** to the implementation: for `DM.EXPOSED`, integrity-protect the stored data using a MAC, signature, or AEAD scheme. - The verification of data integrity must be implemented within the storage service in the :term:`PRoT`, otherwise the result could be spoofed. - - `M.ReplayProtection`. - **Transfer** to the implementation: for `DM.AUTHORIZED` and `DM.SECURE_LINK`, if the channel protocol includes replay protection, the storage medium will check the nonce for freshness, and prevent replay of old messages. - - :mitigation:`AntiRollback`. - **Transfer** to the implementation: in `DM.EXPOSED`, `M.MAC` is insufficient to prevent an attacker from replacing one version of stored data --- or the entire contents of the storage medium --- with a previously stored version. - The previously stored data would pass the integrity checks. - - To prevent this attack, the storage service must keep some authentication data in a location the attacker cannot access. - This location could be stored within the :term:`PRoT` partition, that is using the `DM.PROTECTED`, or in a separate secure enclave using the deployment model `DM.AUTHORIZED` or `DM.SECURE_LINK`. - The data could be the root of a hash tree, or it could be a counter used with a root key to generate a version-specific MAC key. - - In the case of a counter, some consideration should be given to the expected number of updates that will be made to the data. - If the implementation only needs to offer rollback protection on firmware updates, where a low number is expected in the lifetime of the product and the counter could be stored in fuse. - If the implementations needs to ensure the currency of a file store that is regularly updated --- the number of updates could exhaust any practical number of fuses and would instead need a 32-bit counter. - - - .. unmitigated:: DM.PROTECTED - :impact: VH - :likelihood: n/a - :risk: n/a - - .. residual:: DM.PROTECTED - :impact: VH - :likelihood: n/a - :risk: n/a - - .. unmitigated:: DM.EXPOSED - :impact: VH - :likelihood: VH - - .. residual:: DM.EXPOSED - :impact: VH - :likelihood: VL - - .. unmitigated:: DM.AUTHORIZED - :impact: VH - :likelihood: H - - .. residual:: DM.AUTHORIZED - :impact: H - :likelihood: VL - - .. unmitigated:: DM.SECURE_LINK - :impact: H - :likelihood: H - - .. residual:: DM.SECURE_LINK - :impact: H - :likelihood: VL - - -.. threat:: Physical replacement of the storage medium - :id: REPLACE - - .. description:: An attacker might physically replace the storage medium. - - For `DM.PROTECTED`, it is not possible to replace the storage. - - For `DM.EXPOSED`, if the storage medium is integrated with the chip, it is not possible to replace the storage. - But in many systems, the storage medium will be on a separate device. - - For `DM.AUTHORIZED` and `DM.SECURE_LINK`, it is possible to replace the storage medium. - - .. adversarial-model:: `AM.3` - - .. security-goal:: `SG.INTEGRITY` - - .. unmitigated:: DM.PROTECTED - :impact: VH - :likelihood: n/a - :risk: n/a - - .. residual:: DM.PROTECTED - :impact: VH - :likelihood: n/a - :risk: n/a - - .. unmitigated:: DM.EXPOSED - :impact: VH - :likelihood: VH - - .. residual:: DM.EXPOSED - :impact: VH - :likelihood: VL - - .. unmitigated:: DM.AUTHORIZED - :impact: VH - :likelihood: H - - .. residual:: DM.AUTHORIZED - :impact: H - :likelihood: VL - - .. unmitigated:: DM.SECURE_LINK - :impact: VH - :likelihood: H - - .. residual:: DM.SECURE_LINK - :impact: H - :likelihood: VL - - .. mitigations:: - `M.UniqueKeys` and `M.MAC`. - **Transfer** to the implementation: for `DM.EXPOSED`, use device-specific secret keys to authenticate the stored data. - With unique authentication keys, data stored on one device cannot be verified on another device. - - `M.UniqueKeys` and `M.VerifyReplies`. - **Transfer** to the implementation: for `DM.AUTHORIZED` and `DM.SECURE_LINK`, use device-specific secret keys to authenticate the communication between the storage service and storage medium. - - In `DM.AUTHORIZED`, the attacker will not be able to find a new instance of the storage medium that can form the correct responses to commands. - - In `DM.SECURE_LINK`, the attacker will not be able to find a new instance of the storage medium that can complete the handshake to set up the secure channel. - -.. threat:: Glitching during a read - :id: GLITCH_READ - - .. description:: An attacker with physical access might be able to disrupt the power or clock to cause a misread. - - In this threat, an attacker with physical access to the device causes a power or frequency glitch to cause a misread. - In particular, it might prevent the storage service from performing the verification of replies or causing it to ignore the result of any check. - Thus, causing the storage service to return an incorrect value to the caller. - - .. adversarial-model:: `AM.3` - - .. security-goal:: `SG.INTEGRITY` - - .. unmitigated:: DM.PROTECTED - :impact: VH - :likelihood: H - - .. residual:: DM.PROTECTED - :impact: VH - :likelihood: L - - .. unmitigated:: DM.EXPOSED - :impact: VH - :likelihood: H - - .. residual:: DM.EXPOSED - :impact: VH - :likelihood: VL - - .. unmitigated:: DM.AUTHORIZED - :impact: VH - :likelihood: L - - .. residual:: DM.AUTHORIZED - :impact: VH - :likelihood: VL - - .. unmitigated:: DM.SECURE_LINK - :impact: VH - :likelihood: L - - .. residual:: DM.SECURE_LINK - :impact: VH - :likelihood: VL - - .. mitigations:: - :mitigation:`GlitchDetection`. - **Transfer** to the implementation: for all deployment models, active glitch detection circuits can raise an exception if a glitch is detected, permitting the computing circuitry to take corrective action. - - -.. threat:: Glitching during a write - :id: GLITCH_WRITE - - .. description:: An attacker with physical access might be able to disrupt the power or clock to prevent a write from being completed. - - In this threat, an attacker with physical access to the device causes a power or frequency glitch to cause a write to fail. - - .. adversarial-model:: `AM.3` - - .. security-goal:: `SG.INTEGRITY` - - .. unmitigated:: DM.PROTECTED - :impact: VH - :likelihood: H - - .. residual:: DM.PROTECTED - :impact: VH - :likelihood: L - - .. unmitigated:: DM.EXPOSED - :impact: VH - :likelihood: H - - .. residual:: DM.EXPOSED - :impact: VH - :likelihood: VL - - .. unmitigated:: DM.AUTHORIZED - :impact: VH - :likelihood: H - - .. residual:: DM.AUTHORIZED - :impact: H - :likelihood: VL - - .. unmitigated:: DM.SECURE_LINK - :impact: VH - :likelihood: H - - .. residual:: DM.SECURE_LINK - :impact: H - :likelihood: VL - - .. mitigations:: - `M.MAC`. - **Transfer** to the implementation: - - * For `DM.PROTECTED` and `DM.EXPOSED`, if the implementation applies a MAC, a subsequent read can detect that data had not been written correctly. - However, MAC's are not error correcting, therefore the implementation can only mark the data as corrupt and the data is lost. - - * For `DM.AUTHORIZED` and `DM.SECURE_LINK`, if the implementation relies on the channel to provide the MAC or tag, there is a brief time of check, time of use (TOCTOU) window, where the storage medium has verified the command but has not written the data to physical storage. - If a glitch occurs in this window, and then a subsequent read occurs, the storage medium will apply a new tag to a reply containing corrupt data, and the storage service will not be aware that that data returned has been corrupted. - However, if the storage service applies a MAC before submitting the command, it can detect, but not correct, this corruption. - - :mitigation:`ErrorCorrectingCoding`. - **Transfer** to the implementation: for all deployment models, if the storage medium uses error correcting codes (ECC), it can detect and correct a certain number of incorrect bits in the data it reads back --- at the expense of extra storage. - If the storage medium does not offer ECC capability, the storage service could apply it and verify the coding in software, although this is generally less efficient than hardware. - - `M.GlitchDetection`. - **Transfer** to the implementation: for all deployment models, glitch detection can reduce the risk of a successful glitch. - - :mitigation:`ReadAfterWrite`. - **Transfer** to the implementation: for all deployment models, perform a checked-read after a write in the storage service. - The storage service can perform a read operation immediately after a write, while it still retains the original value in memory, and compare the two before reporting a successful write. - However, this has performance challenges: therefore, the implementation can decide to do this on a sampling basis. - - -.. _sra-mitigations: - -Mitigation Summary ------------------- - -This section provides a summary of the mitigations described in the threat analysis, organized by the entity responsible for providing the mitigation. - -Architecture level mitigations -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:numref:`tab-sra-architecture` lists the mitigations that are controlled by the architecture. - -.. list-table:: Mitigations that are **controlled** by the Architecture - :name: tab-sra-architecture - :widths: 1 2 1 - :header-rows: 1 - :class: longtable - - * - Mitigations - - Description - - Threats - - * - `M.MemoryBuffer` - - In all deployment models, input buffers are fully consumed by the implementation before returning from a function. - - `T.INTERFACE_ABUSE` - -Implementation-level mitigations -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:numref:`tab-sra-remediations` lists the mitigations that are transferred to the implementation. -These are also known as 'remediations'. - -.. list-table:: Mitigations that are **transferred** to the implementation - :name: tab-sra-remediations - :widths: 1 2 1 - :header-rows: 1 - :class: longtable - - * - Mitigations - - Description - - Threats - - * - `M.AntiRollback` - - When using `DM.EXPOSED`, the implementation must provide a mechanism to prevent an attacker from replacing the stored data with a version that was valid at a previous date. - An attacker can use this attack to reinstate flawed firmware, or to return to a version with a broken credential. - - `T.DIRECT_WRITE` - - * - `M.AuthenticateEndpoints` - - When using `DM.AUTHORIZED` or `DM.SECURE_LINK`, the storage service must authenticate the storage medium before reading from it or writing to it. - - `T.MITM` - - * - `M.Encrypt` - - When using `DM.EXPOSED` or `DM.AUTHORIZED`, the storage service must encrypt data to be written to storage, and decrypt data read from storage, inside the isolated environment to ensure confidentiality. - - `T.EAVESDROPPING`, `T.MITM`, `T.DIRECT_READ`, `T.DIRECT_WRITE` - - * - `M.ErrorCorrectingCoding` - - In all deployments, to deter attacks based on glitching the power or clock, the implementation can implement error correcting coding on stored data. - - `T.GLITCH_WRITE` - - * - `M.FullyQualifiedNames` - - In all deployments, the implementation must identify which caller each stored object belongs to and must refer to them internally by the combination of caller identity and name. - Otherwise, it might return a stored object to the wrong caller. - - `T.SPOOF_READ`, `T.SPOOF_WRITE` - - * - `M.ImplicitIdentity` - - In all deployments, the implementation must identify the caller. - - `T.SPOOF_READ`, `T.SPOOF_WRITE` - - * - `M.GlitchDetection` - - In all deployments, to deter attacks based on glitching the power or clock, the implementation can implement detection circuits. - - `T.GLITCH_READ`, `T.GLITCH_WRITE` - - * - `M.MAC` - - In `DM.EXPOSED`, the storage service must apply an integrity check, a MAC, signature, or authenticated encryption tag, within the storage service before it is sent to storage. - It must also verify this on every read. - - `T.MITM`, `T.DIRECT_WRITE`, `T.REPLACE` - - * - `M.PRoTRootedSecLink` - - In `DM.SECURE_LINK`, the storage service must use a secure channel rooted within the isolated environment to ensure there is no opportunity for eavesdropping. - - `T.EAVESDROPPING` - - * - `M.ReadAfterWrite` - - To deter glitch attacks on writing data, the implementation can read the data it has just written to verify it. - - `T.GLITCH_WRITE` - - * - `M.ReplayProtection` - - In `DM.AUTHORIZED` and `DM.SECURE_LINK` there must be protection against an attacker replaying previous messages. - - `T.DIRECT_READ`, `T.DIRECT_WRITE` - - * - `M.UniqueKeys` - - In `DM.AUTHORIZED` and `DM.SECURE_LINK` the keys used by the storage service and storage medium must be unique, otherwise there is no mechanism for detecting that the storage medium has been replaced. - - `T.MITM`, `T.REPLACE` - - * - `M.ValidateParameter` - - In all deployment models, check all API parameters to lie within valid ranges, including memory access permissions. - - `T.INTERFACE_ABUSE` - - * - `M.VerifyReplies` - - In `DM.AUTHORIZED` and `DM.SECURE_LINK` the storage service must verify all replies from the partition that implements storage, to ensure that they do indeed come from the expected partition and no errors are reported. - - `T.MITM`, `T.REPLACE` - - -User-level mitigations -^^^^^^^^^^^^^^^^^^^^^^ - -:numref:`tab-sra-residual-risk` lists mitigations that are transferred to the application or other external components. -These are also known as 'residual risks'. - -.. list-table:: Mitigations that are **transferred** to the application - :name: tab-sra-residual-risk - :widths: 1 2 1 - :header-rows: 1 - :class: longtable - - - * - Mitigations - - Description - - Threats - - * - `M.UseSecurePartitions` - - In all deployments, if the caller wants to be certain that there is no chance of eavesdropping, they should make use of caller isolation, with each caller in its own isolated partition. - - `T.EAVESDROPPING` - -Mitigations required by each deployment model -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:numref:`tab-sra-api-mitigations` summarizes the mitigations required in each deployment model. - -.. list-table:: Mitigations required by each deployment model - :name: tab-sra-api-mitigations - :widths: 1 3 - :header-rows: 1 - :class: longtable - - * - Implementation - - Mitigations - - - * - `DM.PROTECTED` - - `M.ErrorCorrectingCoding`, - `M.FullyQualifiedNames`, - `M.GlitchDetection`, - `M.ImplicitIdentity`, - `M.MemoryBuffer`, - `M.ReadAfterWrite`, - `M.UseSecurePartitions`, - `M.ValidateParameter` - - * - `DM.EXPOSED` - - `M.AntiRollback`, - `M.Encrypt`, - `M.ErrorCorrectingCoding`, - `M.FullyQualifiedNames`, - `M.GlitchDetection`, - `M.ImplicitIdentity`, - `M.MAC`, - `M.MemoryBuffer`, - `M.ReadAfterWrite`, - `M.UseSecurePartitions`, - `M.ValidateParameter` - - * - `DM.AUTHORIZED` - - `M.AuthenticateEndpoints`, - `M.ErrorCorrectingCoding`, - `M.FullyQualifiedNames`, - `M.GlitchDetection`, - `M.ImplicitIdentity`, - `M.MemoryBuffer`, - `M.ReadAfterWrite`, - `M.ReplayProtection`, - `M.UniqueKeys`, - `M.UseSecurePartitions`, - `M.VerifyReplies`, - `M.ValidateParameter` - - * - `DM.SECURE_LINK` - - `M.AuthenticateEndpoints`, - `M.ErrorCorrectingCoding`, - `M.FullyQualifiedNames`, - `M.GlitchDetection`, - `M.ImplicitIdentity`, - `M.MemoryBuffer`, - `M.PRoTRootedSecLink`, - `M.ReadAfterWrite`, - `M.ReplayProtection`, - `M.UniqueKeys`, - `M.UseSecurePartitions`, - `M.VerifyReplies`, - `M.ValidateParameter` - - -In implementations `DM.PROTECTED` and `DM.SECURE_LINK`, the stored data can be implicitly trusted, and therefore it is not required to be encrypted or authenticated. -There is no more secure location to store verification data, therefore, any attacker able to access the stored data would also be able to access the key. -However, it is possible for the data to be accidentally corrupted, therefore standard engineering practice to guard against this, for example the use of error correcting codes, should be used. - -In implementation `DM.EXPOSED`, the data can be read or modified by an attacker, therefore the storage service must provide confidentiality, integrity, and authenticity by cryptographic means. -The keys used to do this must be stored securely. -This could be a key derived from the HUK, or separately stored in fuse in a location only readable from the :term:`PRoT`. - -As the attacker can always read and modify the stored data, even if they cannot decrypt the data, they can attempt to subvert a change by resetting the storage medium to a prior state. -To detect this, the storage service needs to have some means of authenticating that it is reading the most recent state. -This implies some form of authentication data stored in a location the attacker cannot modify. - -In implementation `DM.AUTHORIZED`, the data can be observed, even if it cannot be modified. -Therefore, data stored does need to be encrypted for confidentiality. -However, provided the authentication protocol is strong, and prevents replay, it should not be possible for an attacker to modify the stored data. -As the store applies a MAC to each reply, the storage service does not need to apply extra integrity. - -In implementation `DM.SECURE_LINK` provided the secure channel is rooted within the :term:`PRoT`, the data transferred cannot be observed, and any modification will be detected. -Therefore, no further encryption is needed for confidentiality or integrity. +.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +.. _sra: + +Security Risk Assessment +======================== + +This appendix provides a Security Risk Assessment (SRA) of the |API| and of a generic implementation of storage. +It describes the threats presented by various types of adversaries against the security goals for an implementation of a secure storage service, and mitigating actions for those threats. + +* :secref:`sra-about` describes the assessment methodology. +* :secref:`sra-definition` defines the security problem. +* :secref:`sra-threats` describes the threats and the recommended mitigating actions. +* :secref:`sra-mitigations` summarizes the mitigations, and where these are implemented. + +.. _sra-about: + +About this assessment +--------------------- + +Subject and scope +^^^^^^^^^^^^^^^^^ + +This SRA analyses the security of the |API| itself, and of the conceptual architectures for storage, not of any specific implementation of the API, or any specific use of the API. +It does, however, divide implementations into four deployment models representing common implementation types, and looks at the different mitigations needed in each deployment model. + +In this SRA: + +* *Storage service* means the firmware implementing the |API|. +* *Storage medium* refers to the physical storage location. + +Risk assessment methodology +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Our risk ratings use an approach derived from :cite-title:`SP800-30`: for each Threat, we determine its Likelihood and the Impact. +Each is evaluated on a 5-level scale, as defined in :numref:`tab-sra-likelihood` and :numref:`tab-sra-impact`. + +.. list-table:: Likelihood levels + :name: tab-sra-likelihood + :header-rows: 1 + :stub-columns: 1 + :widths: 1 6 + + * - Level + - Definition + + * - Very Low + - Unlikely to ever occur in practice, or *mathematically near impossible* + * - Low + - The event could occur, but only if the attacker employs *significant* resources; or it is *mathematically unlikely* + * - Medium + - A motivated, and well-equipped adversary can make it happen within the lifetime of a product based on the feature (resp. of the feature itself) + * - High + - Likely to happen within the lifetime of the product or feature + * - Very High + - Will happen, and soon (for instance a zero-day) + +.. list-table:: Impact levels + :name: tab-sra-impact + :header-rows: 1 + :stub-columns: 1 + :widths: 1 3 3 + + * - Level + - Definition + - Example Effects + + * - Very Low + - Causes virtually no damage. + - Probably none. + * - Low + - The damage can easily be tolerated or absorbed. + - There would be a CVE at most. + * - Medium + - The damage will have a *noticeable* effect, such as *degrading* some functionality, but won't degrade completely the use of the considered functionality. + - There would be a CVE at most. + * - High + - The damage will have a *strong* effect, such as causing a significant reduction in its functionality or in its security guarantees. + - Security Analysts would discuss this at length, there would be papers, blog entries. + Partners would complain. + * - Very High + - The damage will have *critical* consequences --- it could kill the feature, by affecting several of its security guarantees. + - It would be quite an event. + + Partners would complain strongly, and delay or cancel deployment of the feature. + +For both Likelihood and Impact, when in doubt always choose the higher value. +These two values are combined using :numref:`tab-sra-overall-risk` to determine the Overall Risk of a Threat. + +.. csv-table:: Overall risk calculation + :name: tab-sra-overall-risk + :header-rows: 2 + :stub-columns: 1 + :align: right + + ,Impact,,,, + Likelihood, Very Low, Low, Medium, High, Very High + Very Low, Very Low, Very Low, Very Low, Low, Low + Low, Very Low, Very Low, Low, Low, Medium + Medium, Very Low, Low, Medium, Medium, High + High, (Very) Low, Low, Medium, High, Very High + Very High, (Very) Low, Medium, High, Very High, Very High + +Threats are handled starting from the most severe ones. +Mitigations will be devised for these Threats one by one (note that a Mitigation may mitigate more Threats, and one Threat may require the deployment of more than one Mitigation to be addressed). +Likelihood and Impact will be reassessed assuming that the Mitigations are in place, resulting in a Mitigated Likelihood (this is the value that usually decreases), a Mitigated Impact (it is less common that this value will decrease), and finally a Mitigated Risk. +The Analysis is completed when all the Mitigated Risks are at the chosen residual level or lower, which usually is Low or Very Low. + +The Mitigating actions that can be taken are defined in the acronym **CAST**: + +* **Control**: Put in place steps to reduce the Likelihood and/or Impact of a Threat, thereby reducing the risk to an acceptable level. +* **Accept**: The threat is considered to be of acceptable risk such that a mitigation is not necessary or must be accepted because of other constraint or market needs. +* **Suppress**: Remove the feature or process that gives rise to the threat. +* **Transfer**: Identify a more capable or suitable party to address the risk and transfer the responsibility of providing a mitigation for the threat to them. + +.. _sra-definition: + +Feature definition +------------------ + +Introduction +^^^^^^^^^^^^ + +Background +~~~~~~~~~~ + +:secref:`introduction` provides the context in which the |API| is designed. + +Purpose +~~~~~~~ + +The |API| separates the software responsible for providing the security of the data from the caller. +The storage service calls on firmware that provides low level reads and writes of non-volatile storage medium and the access to any required bus. +The |API| is to provide a consistent interface, so that applications do not need to account for the different low-level implementations. + +This analysis does not address the engineering requirements to create a reliable storage medium from the underlying physical storage. +It is assumed that the implementation will use the standard techniques, error correcting codes, wear levelling and so on, to ensure the storage is reliable. + +Lifecycle +^^^^^^^^^ + +:numref:`fig-lifecycle` shows the typical lifecycle of a device. + +.. figure:: /figure/lifecycle.* + :name: fig-lifecycle + + Device lifecycle of a system providing storage + +The storage service, and the |API| are active during the operational phase, implemented within the boot-time and run-time software. + +Within a boot session, it is the responsibility of the secure boot firmware to: + +* Set up the isolation barriers between partitions. +* Provision the firmware implementing the storage service. +* Provision the credentials for authorizing the storage of data. +* Enable or disable debug facilities. + +This SRA only considers threats to the storage service in its operational phase. +The security of the boot process and of any data provisioning service are not considered in this SRA. + +Operation and trust boundaries +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:numref:`fig-boundaries` shows all of the main components in the storage service. +Presenting the context in which the |API| operates aids understanding of the threats and security mitigations and provides justification for some of the aspects of the API design. + +.. figure:: /figure/callers.* + :name: fig-boundaries + + Trust boundaries of a system providing storage + +|API| is a C language API. +Therefore, any implementation of the API must execute, at least partially, within the context of the caller. +When an implementation includes a trust boundary, the mechanism and protocol for communication across the boundary is not defined by this specification. + +The operational dataflow diagram is reproduced for each of the deployment models. +Although the dataflow itself is common to the models, the placement of trust boundaries is different. + +It is helpful to visualize the effect of these differences on the threats against the dataflows. + + +Deployment models +^^^^^^^^^^^^^^^^^ + +:deployment-model:`PROTECTED` + The storage service and all physical storage is within the :term:`Platform Root of Trust` (:term:`PRoT`) partition. + The :term:`PRoT` partition has sole access to an area of non-volatile storage, thus that storage cannot be accessed by any other partition or any other means. + This means that the storage service, any driver code, the storage service and storage medium all reside with the :term:`PRoT` and are protected by the :term:`PRoT`'s isolation mechanisms as shown in :numref:`fig-protected`. + + .. figure:: /figure/dm-protected.* + :name: fig-protected + + Trust boundaries in the deployment model `DM.PROTECTED` + + The storage service is the arbitrator of access from different applications and manages all data accesses (write, update and deletion). + Therefore, the storage service is responsible for the `SG.CONFIDENTIALITY`, `SG.INTEGRITY` and `SG.CURRENCY` goals of each caller, including maintaining confidentiality between different callers. + + An example of this deployment model is the use of on-chip flash or OTP with an access control mechanism such as a Memory Protection Unit. + +:deployment-model:`EXPOSED` + The :term:`PRoT` partition does not have sole access to the area of non-volatile storage, thus the storage medium can be read or written by another partition or by other means. + This means that the driver code, or the storage medium resides outside the :term:`PRoT` and is accessible to other partitions or by other means, as shown in as shown in :numref:`fig-exposed`. + Therefore, attackers can bypass the storage service. + + .. figure:: /figure/dm-exposed.* + :name: fig-exposed + + Trust boundaries in the deployment model `DM.EXPOSED` + + The storage service is the arbitrator of access from different applications and manages accesses that write, update, and delete data. + Therefore, the storage service is responsible for the `SG.CONFIDENTIALITY`, `SG.INTEGRITY` and `SG.CURRENCY` goal with respect to preventing access by a different caller. + + The storage service cannot prevent other partitions or other means from reading or writing the storage, or accessing the link DF3. + Therefore, the storage service is responsible for the `SG.CONFIDENTIALITY`, `SG.INTEGRITY` and `SG.CURRENCY` goals. + + An example of this deployment model is the use of a file system on a flash chip. + + +:deployment-model:`AUTHORIZED` + There is a separate isolated storage medium that can only be accessed in response to an authenticated command and from which all replies include a means for verification of the response, as shown in :numref:`fig-authorized`. + The isolation guarantees that there is no access to the storage medium other than by using the authentication mechanism. + + .. figure:: /figure/dm-authorized.* + :name: fig-authorized + + Trust boundaries in the deployment model `DM.AUTHORIZED` + + The storage service is the arbitrator of access from different applications and manages those data accesses (write, update and deletion). + Therefore, the storage service is responsible for the `SG.CONFIDENTIALITY` goal with respect to preventing access by a different caller. + + The authorization and verification mechanism provided by the storage medium controls access to data (reads, writes and modification). + Therefore, the storage medium is responsible for the `SG.INTEGRITY` and `SG.CURRENCY` goals. + Attacks on these mechanisms are out of scope. + + However, the communication between the storage service and the storage medium is observable by other partitions and any other means as any data sent in plain text can be observed. + Therefore, the storage service is responsible for `SG.CONFIDENTIALITY`. + + The storage service and the storage medium are jointly responsible for protecting the assets required to authorize commands. + Attacks on the storage service that expose these assets are in scope. + + An example of this deployment model is the use of an RPMB memory block. + +:deployment-model:`SECURE_LINK` + There is a separate isolated storage medium that can only be accessed across a cryptographically protected secure channel as shown in :numref:`fig-external-secure`. + The secure channel protocol provides authentication, confidentiality and integrity of data in transit. + The isolation guarantees that there is no access to the storage medium other than by using this channel. + + .. figure:: /figure/dm-secure-link.* + :name: fig-external-secure + + Trust boundaries in the deployment model `DM.SECURE_LINK` + + The storage service is the arbitrator of access from different applications and manages those data accesses (write, update and deletion). + Therefore, the storage service is responsible for the `SG.CONFIDENTIALITY` goal with respect to preventing access by a different caller. + + The authorization and verification mechanism provided by the secure channel protocol controls access to data (reads, writes and modification). + Therefore, the storage medium is responsible for the `SG.INTEGRITY` and `SG.CURRENCY` goals. + Attacks on the storage medium are out of scope. + + The communication between the storage service and the storage medium is protected from observation by other partitions and other means as the data is sent in encrypted form over the secure channel. + Attacks on the secure channel protocol are out of scope. + + The storage service uses the secure channel protocol, the storage service and the storage medium are jointly responsible for protecting the assets required to set up the channel. + Attacks on the storage service that expose these assets are in scope. + + An example of this deployment model is the use of a Secure Element, or a secure flash device. + + +.. _isolation: + +Optional isolation +~~~~~~~~~~~~~~~~~~ + +Implementations can isolate the storage service from the caller and can further isolate multiple calling applications. +Various technologies can provide protection, for example: + +* Process isolation in an operating system. +* Partition isolation, either with a virtual machine or a partition manager. +* Physical separation between execution environments. + +The mechanism for identifying callers is beyond the scope of this specification. +An implementation that provides caller isolation must document the identification mechanism. +An implementation that provides caller isolation must document any implementation-specific extension of the API that enables callers to share data in any form. + +In summary, there are three types of implementation: + +* No isolation: there is no security boundary between the caller and the storage service. + For example, a statically or dynamically linked library is an implementation with no isolation. + As the caller is in the same security domain as the storage, the API cannot prevent access to the storage medium that does not go through the API. + +* Simple Isolation: A single security boundary separates the storage service from the callers, but there is no isolation between callers. + The only access to stored data is via the storage service, but the storage service cannot partition data between different callers. + +* Caller isolation: there are multiple caller instances, with a security boundary between the caller instances among themselves, as well as between the storage service and the caller instances. + For example, a storage service in a multiprocessor environment is an implementation with caller isolation. + The only access to the stored data is via the storage service and the storage service can partition stored data between the different callers. + +Assumptions, constraints, and interacting entities +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This SRA makes the following assumptions about the |API| design: + +* The API does not provide arguments that identify the caller, because they can be spoofed easily, and cannot be relied upon. + It is assumed that the implementation of the API can determine the caller identity, where this is required. + See :secref:`isolation`. + +* The API does not prevent the use of mitigations that are required by an implementation of the API. + See :secref:`tab-sra-remediations`. + +* The :cite-title:`PSM` assumes that at least the code in the :term:`Root of Trust` partitions (:term:`PRoT` and :term:`ARoT`) are verified at boot, and on any update. + Therefore, it is assumed that this code is trustworthy. + If any malicious code can run in the RoT partitions, it has achieved full control. + +* For the purposes of this analysis, it is assumed that in deployment models `DM.AUTHORIZED` and `DM.SECURE_LINK`, there is no way to access the stored data without going through the authenticated channel. + That is, an attack that would expose the physical storage medium is beyond the resources of the attacker. + +* The analysis ignores attacks that only result in a denial of service. + There are many ways an attacker can deny service to the complete system, with or without involving the storage service. + +* The analysis only looks at an active attack. + However, data is also subject to accidental modification, for example from cosmic radiation causing a bit flip. + Therefore, standard engineering practice --- such as use of error correcting codes --- should be taken to protect data. + +Stakeholders and Assets +^^^^^^^^^^^^^^^^^^^^^^^ + +This analysis looks at the security from the point of view of the applications that call on the service to store data, and on the overall system. + +The following assets are considered in this assessment: + +Data to be stored + The purpose of a storage service is to securely store data for its callers. + +Caller Identities + To ensure that data stored for one caller is not revealed to a different caller, each caller must have a unique identity. + +Implementation Secrets + If in order to secure the data, the storage service uses encryption keys for confidentiality and integrity, these mut be considered assets of the storage service. + +Goals +^^^^^ + +:security-goal:`CONFIDENTIALITY` + An adversary is unable to disclose Stored Data that belongs to a different Stored Data Owner. + A legitimate owner can guarantee their data has not been exposed. + +:security-goal:`INTEGRITY` + An adversary is unable to modify Stored Data that belongs to a different Stored Data Owner, to a value that was not previously stored by the Stored Data Owner. + A legitimate owner can guarantee that data returned is a value they have stored. + +:security-goal:`CURRENCY` + An adversary is unable to modify Stored Data that belongs to a different Stored Data Owner. + The legitimate owner can guarantee that data returned is the most recent value that have stored. + +Adversarial models +^^^^^^^^^^^^^^^^^^ + +Adversarial models are descriptions of capabilities that adversaries of systems implementing the |API| can have, grouped into classes. +The adversaries are defined in this way to assist with threat modelling an abstract API, which can have different implementations, in systems with a wide range of security sensitivity. + +:adversarial-model:`0` + The Adversary is only capable of accessing data that requires neither physical access to a system containing an implementation of the feature nor the ability to run software on it. + This Adversary is intercepting or providing data or requests to the target system via a network or other remote connection. + + For instance, the Adversary can: + + * Read any input and output to the target through external apparatus. + * Provide, forge, replay or modify such inputs and outputs. + * Perform timings on the observable operations being done by the target, either in normal operation or as a response to crafted inputs. + For example, timing attacks on web servers. + +:adversarial-model:`1` + The Adversary can additionally mount attacks from software running on a target processor implementing the feature. + This type of Adversary can run software on the target. + + For instance, the Adversary can: + + * Attempt software exploitation by running software on the target. + * Exploit access to any memory mapped configuration, monitoring, debug register. + * Mount any side channel analysis that relying on software-exposed built-in hardware features to perform physical unit and time measurements. + * Perform software-induced glitching of resources such as Rowhammer, RASpberry or crashing the CPU by running intensive tasks. + +:adversarial-model:`2` + In addition to the above, the Adversary is capable of mounting hardware attacks and fault injection that does not require breaching the physical envelope of the chips. + This type of Adversary has access to a system containing an implementation of the target feature. + + For instance, the Adversary can: + + * Conduct side-channel analysis that requires measurement equipment. + For example, this can utilize leakage sources such as EM emissions, power consumption, photonics emission, or acoustic channels. + * Plug malicious hardware into an unmodified system. + * Gain access to the internals of the target system and interpose the SoC or memory for the purposes of reading, blocking, replaying, and injecting transactions. + * Replace or add chips on the motherboard. + * Make simple, reversible modifications, to perform glitching. + +:adversarial-model:`3` + In addition to all the above, the Adversary can perform invasive SoC attacks. + + For instance, the Adversary can: + + * Decapsulate a chip, via laser or chemical etching, followed by microphotography to reverse engineer the chip. + * Use a focused ion beam microscope to perform gate level modification. + +The adversarial models that are in scope depend on the product requirements. +To ensure that the |API| can be used in a wide range of systems, this assessment considers adversarial models `AM.0`, `AM.1`, and `AM.2` to be in-scope. + +Code in the RoT partitions is assumed to be trustworthy --- and any untrustworthy code running in :term:`PRoT` partitions already has complete control of the target --- therefore, in `AM.1` this SRA only considers threats from malicious actors running in :term:`Non-secure Processing Environment`. + +.. _sra-threats: + +Threats +------- + +Because |API| can be used in a wide range of deployment models and a wide range of threats, not all mitigating actions apply to all deployment models. +As a result, various mitigations are optional to implement, depending on which threats exist in a particular domain of application, and which deployment model is used. + +:numref:`tab-sra-threats` summarizes the threats. + +.. csv-table:: Summary of threats + :name: tab-sra-threats + :class: longtable + :align: left + :widths: 1 3 + :header-rows: 1 + + Threat, Description + `T.INTERFACE_ABUSE`, Call the API with illegal inputs + `T.SPOOF_READ`, Reading data for a different caller using the API + `T.SPOOF_WRITE`, Writing data for a different caller using the API + `T.EAVESDROPPING`, Accessing data in transit + `T.MITM`, A Man in the Middle can actively interfere with communication + `T.DIRECT_READ`, "Directly reading stored data, bypassing the API" + `T.DIRECT_WRITE`, "Directly modifying data, bypassing the API" + `T.REPLACE`, Physical replacement of the storage medium + `T.GLITCH_READ`, Glitching during a read + `T.GLITCH_WRITE`, Glitching during a write + +.. threat:: Illegal inputs to the API + :id: INTERFACE_ABUSE + + .. description:: + An attacker can abuse the |API|. + For example: + + * Passing out of range values to the interface to provoke unexpected behavior of the implementation. + * Passing invalid input or output buffers to the interface, that would cause the implementation to access non-existent memory, or memory that is inaccessible to the caller --- including accessing assets of the storage service. + + .. security-goal:: `SG.CONFIDENTIALITY`, `SG.INTEGRITY` + .. adversarial-model:: `AM.1` + + .. mitigations:: + :mitigation:`ValidateParameter`. + **Transfer** to the implementation: check all API parameters to lie within valid ranges, including memory access permissions. + + :mitigation:`MemoryBuffer`. + **Control** by API design: input buffers are fully consumed by the implementation before returning from a function. + An implementation must not access the caller's memory after a function has returned. + + .. unmitigated:: + :impact: VH + :likelihood: VH + + .. residual:: + :impact: VH + :likelihood: VL + + +.. threat:: Use the API to read another caller's data + :id: SPOOF_READ + + .. description:: + In all deployment models, an attacker attempts to read data stored for another caller using the |API|. + + The API does not require that the names used by caller for stored data are globally unique, only unique within that caller's namespace. + + .. mitigations:: + :mitigation:`ImplicitIdentity`. + **Control** by API design: caller identity is not provided by the caller to the API. + If caller identity is supplied by the caller in the API, the identity can be spoofed by another caller. + Using authentication credentials only moves the problem of storing secrets, but does not solve it. + + **Transfer** to the implementation: provide caller identities, to isolate data that belongs to different callers. + The assurance that the storage service can give is limited by the assurance that the implementation can give as to the identity of the caller. + + Where each user runs in a separate partition, the identity can be provided by the partition manager. + Where different users run within a single partition, **Transfer** the responsibility for separating users within that partition to the operating system or run time within that partition. + + :mitigation:`FullyQualifiedNames`. + **Transfer** to the implementation: use a fully-qualified data identifier, that is a combination of an owner identity and the item UID. + The implementation must used the owner identity to ensure that a data request to the storage service does not return data of the same UID, that was stored by a different caller. + + The storage service must also ensure that if a data item with the fully-qualified identifier does not exist, the implementation returns the correct error. + + .. security-goal:: :SG:`CONFIDENTIALITY` + + .. adversarial-model:: `AM.1` + + .. unmitigated:: + :impact: VH + :likelihood: VH + + .. residual:: + :impact: VH + :likelihood: VL + +.. threat:: Use the API to modify another caller's data + :id: SPOOF_WRITE + + .. description:: + In all deployment models, an attacker attempts to write data to a file belonging to another caller using the |API| or create a new file in a different caller's namespace. + + This threat is the counterpart to `T.SPOOF_READ` except that the attacker tries to write data rather than read. + It is therefore subject to the same analysis. + + .. mitigations:: `M.FullyQualifiedNames`, `M.ImplicitIdentity`. + + .. security-goal:: :SG:`CONFIDENTIALITY` + .. adversarial-model:: `AM.1` + + .. unmitigated:: + :impact: VH + :likelihood: VH + + .. residual:: + :impact: VH + :likelihood: VL + +.. threat:: Eavesdropping + :id: EAVESDROPPING + + .. description:: + An attacker accesses data in transit, either between the caller and the storage service, or between the storage service and the storage medium. + + In all deployment models, by the definition of an isolated partition in the :cite-title:`PSM`, transfer within the partition, and transfers between one :term:`Secure Partition` and another are isolated from eavesdroppers. + Therefore, if the caller is in a :term:`Secure Partition`, there is no possibility of an eavesdropper accessing the data. + However, if data is sent or returned to a caller in the :term:`Non-secure Processing Environment` (NSPE), although the data is securely delivered to the :term:`NSPE`, it is exposed to all users in the :term:`NSPE`. + As previously noted, the implementation **transfers** the duty of separating users in the :term:`NSPE` to the OS. + + For deployment model `DM.PROTECTED`, the storage service and the storage medium are isolated. + + In `DM.EXPOSED`, any adversary that can obtain operating system privileges in the :term:`NSPE` will have access to all the memory and will therefore be able to eavesdrop on all data in transit. + + An attacker that is external to the processor, `AM.2`, will be able to exploit an eavesdropping attack if the bus to which the memory is attached is accessible via external pins. + Otherwise, the attack is limited to internal attackers `AM.1`. + + In `DM.AUTHORIZED`, an attacker with access to the bus, or to intermediate data buffers, can eavesdrop and obtain the messages. + + In `DM.SECURE_LINK`, an attacker can only eavesdrop on any data transfer not protected by the secure channel. + + .. mitigations:: + :mitigation:`Encrypt`. + **Transfer** to the implementation: for `DM.EXPOSED` and `DM.AUTHORIZED`, the data at rest must be encrypted. + The storage service must apply the encryption to the data before it leaves the :term:`PRoT` partition. + The encryption mechanism chosen must be sufficiently robust. + The key used for encryption must be sufficiently protected, that is, it must only be available to the storage service. + + :mitigation:`PRoTRootedSecLink`. + **Transfer** to the implementation: for `DM.SECURE_LINK`, communication with the storage medium must be over a well-designed secure channel. + If the secure channel is not rooted in the :term:`PRoT` then any adversary in the partition (`AM.1`), or with access to the partition (`AM.2`), in which the channel terminates will be able to eavesdrop on traffic leaving the :term:`PRoT` before it is encrypted. + The secure channel must be rooted within the PRoT. + However, the stored data does not need to be separately encrypted beyond the protection provided by the secure channel. + The private information required to establish the channel must be suitably protected by both the storage service and the storage medium. + + :mitigation:`UseSecurePartitions`. + **Transfer** to the application: for all deployment models, place callers that handle sensitive data into separate partitions. + To ensure that an attacker in the :term:`NSPE` cannot access the data sent by the caller to the storage service, or the replies the storage service returns to the caller, place all code that needs to use the storage service into one or more :term:`Secure Partition`, with one partition per service. + + + .. security-goal:: :SG:`CONFIDENTIALITY` + + .. adversarial-model:: `AM.0`, `AM.1`, `AM.2` + + .. unmitigated:: DM.PROTECTED + :impact: VH + :likelihood: n/a --- except for transfer of data to clients in the :term:`NSPE` + :risk: n/a + + .. residual:: DM.PROTECTED + :impact: VH + :likelihood: n/a + :risk: n/a + + .. unmitigated:: DM.EXPOSED + :impact: VH + :likelihood: VH + + .. residual:: DM.EXPOSED + :impact: VH + :likelihood: VL + + .. unmitigated:: DM.AUTHORIZED + :impact: VH + :likelihood: H + + .. residual:: DM.AUTHORIZED + :impact: VH + :likelihood: VL + + .. unmitigated:: DM.SECURE_LINK + :impact: VH + :likelihood: H + + .. residual:: DM.SECURE_LINK + :impact: VH + :likelihood: VL + + +.. threat:: Man In The Middle + :id: MITM + + .. description:: + An attacker can actively interfere with communication and replace the transmitted data. + In this threat the SRA only considers attackers between the storage service and the storage medium. + An attacker interposing between the Caller and the storage service is considered under `T.SPOOF_READ` or `T.SPOOF_WRITE`. + + For `DM.PROTECTED`, the storage service and the storage medium are isolated. + + For `DM.EXPOSED`, any code running in the :term:`NSPE` has access to the storage medium and any driver firmware, and therefore can act as a man in the middle, by for example persuading the storage service to write to one buffer, and the storage medium to read from another. + + For `DM.AUTHORIZED`, a man in the middle eavesdrops on data in transit. + + For `DM.SECURE_LINK`, a naive secure channel is vulnerable to a man in the middle attack. + + .. mitigations:: + `M.Encrypt`. + **Transfer** to the implementation: if data is encrypted, a man in the middle cannot know what data is being transferred. + It also means they cannot force a specific value to be stored. + + :mitigation:`MAC`. + **Transfer** to the implementation: for `DM.EXPOSED`, apply a Message Authentication Code or a signature to the stored data, or use an authenticated encryption scheme. If the storage service checks the MAC or tag when data is read back from the storage medium to detect unauthorized modification. + + :mitigation:`UniqueKeys`. + **Transfer** to the implementation: for `DM.AUTHORIZED` and `DM.SECURE_LINK`, use unique keys for securing the authenticated or secure channel. + If the keys used by the storage medium are unique to each instance, as an attacker can only learn the key used on this specific instance. + They cannot construct a class break by discovering the key for every instance. + + :mitigation:`VerifyReplies`. + **Transfer** to the implementation: for `DM.AUTHORIZED`, commands and replies are authenticated by the storage medium. + Therefore, the man in the middle cannot forge a valid reply which indicates that the data has been stored when it has not. + If the storage service validates replies from the storage medium, it can verify that the data it sent was correctly stored, and the data retrieved is the value previously stored. + + :mitigation:`AuthenticateEndpoints`. + **Transfer** to the implementation: for `DM.SECURE_LINK`, use mutual authentication of the storage service and storage medium when setting up the secure channel. + For example, this can be achieved by using a single key, known only to both parties. + + :mitigation:`ReplayProtection`. + **Transfer** to the implementation: for `DM.AUTHORIZED` and `DM.SECURE_LINK`, use replay protection in the communication protocol. + This can be achieved by including a nonce in the construction of protocol messages. + This enables the storage medium to detect attempts to replay previous commands and reject them. + + .. security-goal:: :SG:`INTEGRITY` + .. adversarial-model:: `AM.1`, `AM.2` + + .. unmitigated:: DM.PROTECTED + :impact: VH + :likelihood: n/a + :risk: n/a + + .. residual:: DM.PROTECTED + :impact: VH + :likelihood: n/a + :risk: n/a + + .. unmitigated:: DM.EXPOSED + :impact: VH + :likelihood: VH + + .. residual:: DM.EXPOSED + :impact: VH + :likelihood: VL + + .. unmitigated:: DM.AUTHORIZED + :impact: VH + :likelihood: H + + .. residual:: DM.AUTHORIZED + :impact: H + :likelihood: VL + + .. unmitigated:: DM.SECURE_LINK + :impact: H + :likelihood: H + + .. residual:: DM.SECURE_LINK + :impact: H + :likelihood: VL + + +.. threat:: Bypassing the API to directly read data + :id: DIRECT_READ + + .. description:: + An attacker might be able to read stored data through a mechanism other than the API. + + In `DM.PROTECTED`, no attacker should be able to access the stored data. + + In `DM.EXPOSED`, all attackers can access the data. + + In `DM.AUTHORIZED`, the attacker cannot form valid requests to access data. + It can, however, eavesdrop on a legitimate request and replay it later. + + In `DM.SECURE_LINK`, the attacker cannot form valid requests to access data. + It can, however, eavesdrop on a legitimate request and even if it cannot understand it, it could replay it later. + + .. adversarial-model:: `AM.1`, `AM.2` + + .. security-goal:: :SG:`CONFIDENTIALITY` + + .. mitigations:: + `M.ReplayProtection`. + **Transfer** to the implementation: for `DM.AUTHORIZED` and `DM.SECURE_LINK`, use replay protection in the communication protocol. + + `M.Encrypt`. + **Transfer** to the implementation: for `DM.EXPOSED` and `DM.AUTHORIZED`, encrypting the data prevents disclosure. + + .. unmitigated:: DM.PROTECTED + :impact: VH + :likelihood: n/a + :risk: n/a + + .. residual:: DM.PROTECTED + :impact: VH + :likelihood: n/a + :risk: n/a + + .. unmitigated:: DM.EXPOSED + :impact: VH + :likelihood: VH + + .. residual:: DM.EXPOSED + :impact: VH + :likelihood: VL + + .. unmitigated:: DM.AUTHORIZED + :impact: VH + :likelihood: H + + .. residual:: DM.AUTHORIZED + :impact: H + :likelihood: VL + + .. unmitigated:: DM.SECURE_LINK + :impact: H + :likelihood: H + + .. residual:: DM.SECURE_LINK + :impact: H + :likelihood: VL + + + +.. threat:: Bypassing the API to directly modify data + :id: DIRECT_WRITE + + .. description:: An attacker might be able to modify data stored for another caller. + + In `DM.PROTECTED`, no attacker should be able to access the stored data. + + In `DM.EXPOSED`, the SRA assumes that any attacker capable of running code in the :term:`NSPE` can modify the stored data. + However, assuming it is encrypted, the attacker cannot create the correct ciphertext for chosen plain text. + + In `DM.AUTHORIZED`, although the attacker cannot form a valid command, the attacker can eavesdrop on a legitimate request and replay it later. + + In `DM.SECURE_LINK`, although the attacker cannot form a valid command, the attacker can eavesdrop on a legitimate request and replay it later. + + + .. adversarial-model:: `AM.1` `AM.2` + + .. security-goal:: `SG.INTEGRITY`, `SG.CURRENCY` + + .. mitigations:: + `M.Encrypt`. + **Transfer** to the implementation: encrypted data cannot be modified to an attacker-chosen plaintext value. + However, an attacker can still corrupt the stored data. + + `M.MAC`. + **Transfer** to the implementation: for `DM.EXPOSED`, integrity-protect the stored data using a MAC, signature, or AEAD scheme. + The verification of data integrity must be implemented within the storage service in the :term:`PRoT`, otherwise the result could be spoofed. + + `M.ReplayProtection`. + **Transfer** to the implementation: for `DM.AUTHORIZED` and `DM.SECURE_LINK`, if the channel protocol includes replay protection, the storage medium will check the nonce for freshness, and prevent replay of old messages. + + :mitigation:`AntiRollback`. + **Transfer** to the implementation: in `DM.EXPOSED`, `M.MAC` is insufficient to prevent an attacker from replacing one version of stored data --- or the entire contents of the storage medium --- with a previously stored version. + The previously stored data would pass the integrity checks. + + To prevent this attack, the storage service must keep some authentication data in a location the attacker cannot access. + This location could be stored within the :term:`PRoT` partition, that is using the `DM.PROTECTED`, or in a separate secure enclave using the deployment model `DM.AUTHORIZED` or `DM.SECURE_LINK`. + The data could be the root of a hash tree, or it could be a counter used with a root key to generate a version-specific MAC key. + + In the case of a counter, some consideration should be given to the expected number of updates that will be made to the data. + If the implementation only needs to offer rollback protection on firmware updates, where a low number is expected in the lifetime of the product and the counter could be stored in fuse. + If the implementations needs to ensure the currency of a file store that is regularly updated --- the number of updates could exhaust any practical number of fuses and would instead need a 32-bit counter. + + + .. unmitigated:: DM.PROTECTED + :impact: VH + :likelihood: n/a + :risk: n/a + + .. residual:: DM.PROTECTED + :impact: VH + :likelihood: n/a + :risk: n/a + + .. unmitigated:: DM.EXPOSED + :impact: VH + :likelihood: VH + + .. residual:: DM.EXPOSED + :impact: VH + :likelihood: VL + + .. unmitigated:: DM.AUTHORIZED + :impact: VH + :likelihood: H + + .. residual:: DM.AUTHORIZED + :impact: H + :likelihood: VL + + .. unmitigated:: DM.SECURE_LINK + :impact: H + :likelihood: H + + .. residual:: DM.SECURE_LINK + :impact: H + :likelihood: VL + + +.. threat:: Physical replacement of the storage medium + :id: REPLACE + + .. description:: An attacker might physically replace the storage medium. + + For `DM.PROTECTED`, it is not possible to replace the storage. + + For `DM.EXPOSED`, if the storage medium is integrated with the chip, it is not possible to replace the storage. + But in many systems, the storage medium will be on a separate device. + + For `DM.AUTHORIZED` and `DM.SECURE_LINK`, it is possible to replace the storage medium. + + .. adversarial-model:: `AM.3` + + .. security-goal:: `SG.INTEGRITY` + + .. unmitigated:: DM.PROTECTED + :impact: VH + :likelihood: n/a + :risk: n/a + + .. residual:: DM.PROTECTED + :impact: VH + :likelihood: n/a + :risk: n/a + + .. unmitigated:: DM.EXPOSED + :impact: VH + :likelihood: VH + + .. residual:: DM.EXPOSED + :impact: VH + :likelihood: VL + + .. unmitigated:: DM.AUTHORIZED + :impact: VH + :likelihood: H + + .. residual:: DM.AUTHORIZED + :impact: H + :likelihood: VL + + .. unmitigated:: DM.SECURE_LINK + :impact: VH + :likelihood: H + + .. residual:: DM.SECURE_LINK + :impact: H + :likelihood: VL + + .. mitigations:: + `M.UniqueKeys` and `M.MAC`. + **Transfer** to the implementation: for `DM.EXPOSED`, use device-specific secret keys to authenticate the stored data. + With unique authentication keys, data stored on one device cannot be verified on another device. + + `M.UniqueKeys` and `M.VerifyReplies`. + **Transfer** to the implementation: for `DM.AUTHORIZED` and `DM.SECURE_LINK`, use device-specific secret keys to authenticate the communication between the storage service and storage medium. + + In `DM.AUTHORIZED`, the attacker will not be able to find a new instance of the storage medium that can form the correct responses to commands. + + In `DM.SECURE_LINK`, the attacker will not be able to find a new instance of the storage medium that can complete the handshake to set up the secure channel. + +.. threat:: Glitching during a read + :id: GLITCH_READ + + .. description:: An attacker with physical access might be able to disrupt the power or clock to cause a misread. + + In this threat, an attacker with physical access to the device causes a power or frequency glitch to cause a misread. + In particular, it might prevent the storage service from performing the verification of replies or causing it to ignore the result of any check. + Thus, causing the storage service to return an incorrect value to the caller. + + .. adversarial-model:: `AM.3` + + .. security-goal:: `SG.INTEGRITY` + + .. unmitigated:: DM.PROTECTED + :impact: VH + :likelihood: H + + .. residual:: DM.PROTECTED + :impact: VH + :likelihood: L + + .. unmitigated:: DM.EXPOSED + :impact: VH + :likelihood: H + + .. residual:: DM.EXPOSED + :impact: VH + :likelihood: VL + + .. unmitigated:: DM.AUTHORIZED + :impact: VH + :likelihood: L + + .. residual:: DM.AUTHORIZED + :impact: VH + :likelihood: VL + + .. unmitigated:: DM.SECURE_LINK + :impact: VH + :likelihood: L + + .. residual:: DM.SECURE_LINK + :impact: VH + :likelihood: VL + + .. mitigations:: + :mitigation:`GlitchDetection`. + **Transfer** to the implementation: for all deployment models, active glitch detection circuits can raise an exception if a glitch is detected, permitting the computing circuitry to take corrective action. + + +.. threat:: Glitching during a write + :id: GLITCH_WRITE + + .. description:: An attacker with physical access might be able to disrupt the power or clock to prevent a write from being completed. + + In this threat, an attacker with physical access to the device causes a power or frequency glitch to cause a write to fail. + + .. adversarial-model:: `AM.3` + + .. security-goal:: `SG.INTEGRITY` + + .. unmitigated:: DM.PROTECTED + :impact: VH + :likelihood: H + + .. residual:: DM.PROTECTED + :impact: VH + :likelihood: L + + .. unmitigated:: DM.EXPOSED + :impact: VH + :likelihood: H + + .. residual:: DM.EXPOSED + :impact: VH + :likelihood: VL + + .. unmitigated:: DM.AUTHORIZED + :impact: VH + :likelihood: H + + .. residual:: DM.AUTHORIZED + :impact: H + :likelihood: VL + + .. unmitigated:: DM.SECURE_LINK + :impact: VH + :likelihood: H + + .. residual:: DM.SECURE_LINK + :impact: H + :likelihood: VL + + .. mitigations:: + `M.MAC`. + **Transfer** to the implementation: + + * For `DM.PROTECTED` and `DM.EXPOSED`, if the implementation applies a MAC, a subsequent read can detect that data had not been written correctly. + However, MAC's are not error correcting, therefore the implementation can only mark the data as corrupt and the data is lost. + + * For `DM.AUTHORIZED` and `DM.SECURE_LINK`, if the implementation relies on the channel to provide the MAC or tag, there is a brief time of check, time of use (TOCTOU) window, where the storage medium has verified the command but has not written the data to physical storage. + If a glitch occurs in this window, and then a subsequent read occurs, the storage medium will apply a new tag to a reply containing corrupt data, and the storage service will not be aware that that data returned has been corrupted. + However, if the storage service applies a MAC before submitting the command, it can detect, but not correct, this corruption. + + :mitigation:`ErrorCorrectingCoding`. + **Transfer** to the implementation: for all deployment models, if the storage medium uses error correcting codes (ECC), it can detect and correct a certain number of incorrect bits in the data it reads back --- at the expense of extra storage. + If the storage medium does not offer ECC capability, the storage service could apply it and verify the coding in software, although this is generally less efficient than hardware. + + `M.GlitchDetection`. + **Transfer** to the implementation: for all deployment models, glitch detection can reduce the risk of a successful glitch. + + :mitigation:`ReadAfterWrite`. + **Transfer** to the implementation: for all deployment models, perform a checked-read after a write in the storage service. + The storage service can perform a read operation immediately after a write, while it still retains the original value in memory, and compare the two before reporting a successful write. + However, this has performance challenges: therefore, the implementation can decide to do this on a sampling basis. + + +.. _sra-mitigations: + +Mitigation Summary +------------------ + +This section provides a summary of the mitigations described in the threat analysis, organized by the entity responsible for providing the mitigation. + +Architecture level mitigations +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:numref:`tab-sra-architecture` lists the mitigations that are controlled by the architecture. + +.. list-table:: Mitigations that are **controlled** by the Architecture + :name: tab-sra-architecture + :widths: 1 2 1 + :header-rows: 1 + :class: longtable + + * - Mitigations + - Description + - Threats + + * - `M.MemoryBuffer` + - In all deployment models, input buffers are fully consumed by the implementation before returning from a function. + - `T.INTERFACE_ABUSE` + +Implementation-level mitigations +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:numref:`tab-sra-remediations` lists the mitigations that are transferred to the implementation. +These are also known as 'remediations'. + +.. list-table:: Mitigations that are **transferred** to the implementation + :name: tab-sra-remediations + :widths: 1 2 1 + :header-rows: 1 + :class: longtable + + * - Mitigations + - Description + - Threats + + * - `M.AntiRollback` + - When using `DM.EXPOSED`, the implementation must provide a mechanism to prevent an attacker from replacing the stored data with a version that was valid at a previous date. + An attacker can use this attack to reinstate flawed firmware, or to return to a version with a broken credential. + - `T.DIRECT_WRITE` + + * - `M.AuthenticateEndpoints` + - When using `DM.AUTHORIZED` or `DM.SECURE_LINK`, the storage service must authenticate the storage medium before reading from it or writing to it. + - `T.MITM` + + * - `M.Encrypt` + - When using `DM.EXPOSED` or `DM.AUTHORIZED`, the storage service must encrypt data to be written to storage, and decrypt data read from storage, inside the isolated environment to ensure confidentiality. + - `T.EAVESDROPPING`, `T.MITM`, `T.DIRECT_READ`, `T.DIRECT_WRITE` + + * - `M.ErrorCorrectingCoding` + - In all deployments, to deter attacks based on glitching the power or clock, the implementation can implement error correcting coding on stored data. + - `T.GLITCH_WRITE` + + * - `M.FullyQualifiedNames` + - In all deployments, the implementation must identify which caller each stored object belongs to and must refer to them internally by the combination of caller identity and name. + Otherwise, it might return a stored object to the wrong caller. + - `T.SPOOF_READ`, `T.SPOOF_WRITE` + + * - `M.ImplicitIdentity` + - In all deployments, the implementation must identify the caller. + - `T.SPOOF_READ`, `T.SPOOF_WRITE` + + * - `M.GlitchDetection` + - In all deployments, to deter attacks based on glitching the power or clock, the implementation can implement detection circuits. + - `T.GLITCH_READ`, `T.GLITCH_WRITE` + + * - `M.MAC` + - In `DM.EXPOSED`, the storage service must apply an integrity check, a MAC, signature, or authenticated encryption tag, within the storage service before it is sent to storage. + It must also verify this on every read. + - `T.MITM`, `T.DIRECT_WRITE`, `T.REPLACE` + + * - `M.PRoTRootedSecLink` + - In `DM.SECURE_LINK`, the storage service must use a secure channel rooted within the isolated environment to ensure there is no opportunity for eavesdropping. + - `T.EAVESDROPPING` + + * - `M.ReadAfterWrite` + - To deter glitch attacks on writing data, the implementation can read the data it has just written to verify it. + - `T.GLITCH_WRITE` + + * - `M.ReplayProtection` + - In `DM.AUTHORIZED` and `DM.SECURE_LINK` there must be protection against an attacker replaying previous messages. + - `T.DIRECT_READ`, `T.DIRECT_WRITE` + + * - `M.UniqueKeys` + - In `DM.AUTHORIZED` and `DM.SECURE_LINK` the keys used by the storage service and storage medium must be unique, otherwise there is no mechanism for detecting that the storage medium has been replaced. + - `T.MITM`, `T.REPLACE` + + * - `M.ValidateParameter` + - In all deployment models, check all API parameters to lie within valid ranges, including memory access permissions. + - `T.INTERFACE_ABUSE` + + * - `M.VerifyReplies` + - In `DM.AUTHORIZED` and `DM.SECURE_LINK` the storage service must verify all replies from the partition that implements storage, to ensure that they do indeed come from the expected partition and no errors are reported. + - `T.MITM`, `T.REPLACE` + + +User-level mitigations +^^^^^^^^^^^^^^^^^^^^^^ + +:numref:`tab-sra-residual-risk` lists mitigations that are transferred to the application or other external components. +These are also known as 'residual risks'. + +.. list-table:: Mitigations that are **transferred** to the application + :name: tab-sra-residual-risk + :widths: 1 2 1 + :header-rows: 1 + :class: longtable + + + * - Mitigations + - Description + - Threats + + * - `M.UseSecurePartitions` + - In all deployments, if the caller wants to be certain that there is no chance of eavesdropping, they should make use of caller isolation, with each caller in its own isolated partition. + - `T.EAVESDROPPING` + +Mitigations required by each deployment model +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:numref:`tab-sra-api-mitigations` summarizes the mitigations required in each deployment model. + +.. list-table:: Mitigations required by each deployment model + :name: tab-sra-api-mitigations + :widths: 1 3 + :header-rows: 1 + :class: longtable + + * - Implementation + - Mitigations + + + * - `DM.PROTECTED` + - `M.ErrorCorrectingCoding`, + `M.FullyQualifiedNames`, + `M.GlitchDetection`, + `M.ImplicitIdentity`, + `M.MemoryBuffer`, + `M.ReadAfterWrite`, + `M.UseSecurePartitions`, + `M.ValidateParameter` + + * - `DM.EXPOSED` + - `M.AntiRollback`, + `M.Encrypt`, + `M.ErrorCorrectingCoding`, + `M.FullyQualifiedNames`, + `M.GlitchDetection`, + `M.ImplicitIdentity`, + `M.MAC`, + `M.MemoryBuffer`, + `M.ReadAfterWrite`, + `M.UseSecurePartitions`, + `M.ValidateParameter` + + * - `DM.AUTHORIZED` + - `M.AuthenticateEndpoints`, + `M.ErrorCorrectingCoding`, + `M.FullyQualifiedNames`, + `M.GlitchDetection`, + `M.ImplicitIdentity`, + `M.MemoryBuffer`, + `M.ReadAfterWrite`, + `M.ReplayProtection`, + `M.UniqueKeys`, + `M.UseSecurePartitions`, + `M.VerifyReplies`, + `M.ValidateParameter` + + * - `DM.SECURE_LINK` + - `M.AuthenticateEndpoints`, + `M.ErrorCorrectingCoding`, + `M.FullyQualifiedNames`, + `M.GlitchDetection`, + `M.ImplicitIdentity`, + `M.MemoryBuffer`, + `M.PRoTRootedSecLink`, + `M.ReadAfterWrite`, + `M.ReplayProtection`, + `M.UniqueKeys`, + `M.UseSecurePartitions`, + `M.VerifyReplies`, + `M.ValidateParameter` + + +In implementations `DM.PROTECTED` and `DM.SECURE_LINK`, the stored data can be implicitly trusted, and therefore it is not required to be encrypted or authenticated. +There is no more secure location to store verification data, therefore, any attacker able to access the stored data would also be able to access the key. +However, it is possible for the data to be accidentally corrupted, therefore standard engineering practice to guard against this, for example the use of error correcting codes, should be used. + +In implementation `DM.EXPOSED`, the data can be read or modified by an attacker, therefore the storage service must provide confidentiality, integrity, and authenticity by cryptographic means. +The keys used to do this must be stored securely. +This could be a key derived from the HUK, or separately stored in fuse in a location only readable from the :term:`PRoT`. + +As the attacker can always read and modify the stored data, even if they cannot decrypt the data, they can attempt to subvert a change by resetting the storage medium to a prior state. +To detect this, the storage service needs to have some means of authenticating that it is reading the most recent state. +This implies some form of authentication data stored in a location the attacker cannot modify. + +In implementation `DM.AUTHORIZED`, the data can be observed, even if it cannot be modified. +Therefore, data stored does need to be encrypted for confidentiality. +However, provided the authentication protocol is strong, and prevents replay, it should not be possible for an attacker to modify the stored data. +As the store applies a MAC to each reply, the storage service does not need to apply extra integrity. + +In implementation `DM.SECURE_LINK` provided the secure channel is rooted within the :term:`PRoT`, the data transferred cannot be observed, and any modification will be detected. +Therefore, no further encryption is needed for confidentiality or integrity. diff --git a/doc/storage/conf.py b/doc/storage/conf.py index 28ee2c7f..09f5989f 100644 --- a/doc/storage/conf.py +++ b/doc/storage/conf.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright 2018-2019, 2022-2025 Arm Limited and/or its affiliates +# SPDX-FileCopyrightText: Copyright 2018-2019, 2022-2026 Arm Limited and/or its affiliates # SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license # PSA Certified API document configuration @@ -8,42 +8,34 @@ doc_info = { # Document template - 'template': 'psa-api-2025', + 'template': 'psa-api-2026', # Document title, MANDATORY 'title': 'PSA Certified\nSecure Storage API', 'author': 'Arm Limited', # Document copyright date, default to year of 'date' - 'copyright_date': '2018-2019, 2022-2025', + 'copyright_date': '2018-2019, 2022-2026', 'copyright': 'Arm Limited and/or its affiliates', - # Arm document identifier, marked as open issue if not provided - 'doc_id': 'IHI 0087', + # Document identifier, marked as open issue if not provided + 'doc_id': 'GPD_SPE_087', # The short X.Y version. MANDATORY 'version': '1.0', - # Arm document quality status, marked as open issue if not provided - 'quality': 'REL', - # Arm document issue number (within that version and quality status) - # Marked as open issue if not provided + # Document maintenance revision 'issue_no': 4, - # Identifies the sequence number of a release candidate of the same issue - # default to None - #'release_candidate': 1, - # Draft status - use this to indicate the document is not ready for publication - #'draft': True, - - # Arm document confidentiality. Must be either Non-confidential or Confidential - # Marked as open issue if not provided - 'confidentiality': 'Non-confidential', + # Document draft revision + 'draft': 1, + # Document status + 'status': 'DFT', # Id of the legal notice for this document # Marked as open issue if not provided - 'license': 'psa-certified-api-license', + #'license': 'psa-certified-api-license', # Document date, default to build date - 'date': '23/09/2025', + 'date': 'September 2025', # psa_spec: default header file for API definitions # default to None, and can be set in documentation source @@ -55,9 +47,6 @@ # 2 : Sub-elements of API - parameters, fields, values 'header_doxygen': 2, - # Declare a watermark for the PDF output - #'watermark': 'DRAFT', - # Optional ordering of return error values # This list is used to create a standard ordering of return value responses # throughout the document, irrespective of their ordering in the source text @@ -87,14 +76,12 @@ 'page_break': 'chapter', } -# absolute or relative path to the psa_spec material from this file -# atg_sphinx_spec_dir = '../atg-sphinx-spec' - -# Set up and run the atg-sphinx-spec configuration +# Set up and run the psa-api-tool configuration import os -atg_sphinx_spec_dir = os.environ.get('ATG_SPHINX_SPEC') or atg_sphinx_spec_dir -exec(compile(open(os.path.join(atg_sphinx_spec_dir,'atg-sphinx-conf.py'), +psa_api_tool_path = os.path.normpath(os.path.join(os.path.dirname(__file__), '..', '..', 'tools')) +psa_api_tool_path = os.environ.get('PSA_API_TOOL') or psa_api_tool_path +exec(compile(open(os.path.join(psa_api_tool_path,'psa-api-conf.py'), encoding='utf-8').read(), - 'atg-sphinx-conf.py', 'exec')) + 'psa-api-conf.py', 'exec')) diff --git a/doc/storage/figure/callers.pdf b/doc/storage/figure/callers.pdf index 81a4791a..71b7b2a1 100644 Binary files a/doc/storage/figure/callers.pdf and b/doc/storage/figure/callers.pdf differ diff --git a/doc/storage/figure/callers.puml b/doc/storage/figure/callers.puml index 19910fb8..516469c5 100644 --- a/doc/storage/figure/callers.puml +++ b/doc/storage/figure/callers.puml @@ -1,35 +1,35 @@ ' SPDX-FileCopyrightText: Copyright 2023 Arm Limited and/or its affiliates -' SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license - -@startuml - -!include atg-spec.pumh -!include atg-dataflow.pumh - -skinparam RectangleborderThickness 0 -skinparam RectanglefontColor white -skinparam DatabaseBorderColor #ArmMidGray -skinparam InterfaceBorderColor #ArmMidGray - -left to right direction - -dfd_tb("Application boundary") { - rectangle "Application 1" as caller1 #ArmMidGray - interface "**Secure Storage API**" as api1 #ArmGreen -} -dfd_tb("Data protection boundary") { -rectangle "Storage service" as service #ArmMidBlue -database "Storage medium" as store #ArmLightGray -} -dfd_tb("Application boundary") { - interface "**Secure Storage API**" as api2 #ArmGreen - rectangle "Application 2" as caller2 #ArmMidGray -} - -caller1 -d- api1 -api1 -d-> service -service <--> store -caller2 -d- api2 -api2 -d-> service - -@enduml +' SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +@startuml + +!include psa-spec.pumh +!include psa-dataflow.pumh + +skinparam RectangleborderThickness 0 +skinparam RectanglefontColor white +skinparam DatabaseBorderColor #PSAMidGray +skinparam InterfaceBorderColor #PSAMidGray + +left to right direction + +dfd_tb("Application boundary") { + rectangle "Application 1" as caller1 #PSAMidGray + interface "**Secure Storage API**" as api1 #PSAGreen +} +dfd_tb("Data protection boundary") { +rectangle "Storage service" as service #PSAMidBlue +database "Storage medium" as store #PSALightGray +} +dfd_tb("Application boundary") { + interface "**Secure Storage API**" as api2 #PSAGreen + rectangle "Application 2" as caller2 #PSAMidGray +} + +caller1 -d- api1 +api1 -d-> service +service <--> store +caller2 -d- api2 +api2 -d-> service + +@enduml diff --git a/doc/storage/figure/callers.svg b/doc/storage/figure/callers.svg index 8dd6e67a..3ac0cd92 100644 --- a/doc/storage/figure/callers.svg +++ b/doc/storage/figure/callers.svg @@ -1 +1 @@ -«Application boundary»«Data protection boundary»«Application boundary»Application 1Secure Storage APIStorage serviceStorage mediumSecure Storage APIApplication 2 \ No newline at end of file +«Application boundary»«Data protection boundary»«Application boundary»Application 1Secure Storage APIStorage serviceStorage mediumSecure Storage APIApplication 2 \ No newline at end of file diff --git a/doc/storage/figure/dm-authorized.pdf b/doc/storage/figure/dm-authorized.pdf index bd5fbe8d..cf3d1521 100644 Binary files a/doc/storage/figure/dm-authorized.pdf and b/doc/storage/figure/dm-authorized.pdf differ diff --git a/doc/storage/figure/dm-authorized.puml b/doc/storage/figure/dm-authorized.puml index 6a962e0a..48d172ef 100644 --- a/doc/storage/figure/dm-authorized.puml +++ b/doc/storage/figure/dm-authorized.puml @@ -1,31 +1,31 @@ ' SPDX-FileCopyrightText: Copyright 2023 Arm Limited and/or its affiliates -' SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license - -@startuml - -!include atg-spec.pumh -!include atg-dataflow.pumh - -skinparam RectangleborderThickness 0 -skinparam RectanglefontColor white -skinparam DatabaseBorderColor #ArmMidGray -skinparam InterfaceBorderColor #ArmMidGray - -left to right direction - -dfd_tb("Device ") { - rectangle "Application" as caller #ArmMidGray - interface "**Secure Storage API**" as api #ArmGreen - dfd_tb($label="Platform Root of Trust") { - rectangle "Storage service" as service #ArmMidBlue - } - dfd_tb($label="Replay-Protected\nMemory Block") { - database "Storage medium" as store #ArmLightGray - } -} - -caller -d- api -api -d-> service : DF1 -service <-d-> store : DF4 - -@enduml +' SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +@startuml + +!include psa-spec.pumh +!include psa-dataflow.pumh + +skinparam RectangleborderThickness 0 +skinparam RectanglefontColor white +skinparam DatabaseBorderColor #PSAMidGray +skinparam InterfaceBorderColor #PSAMidGray + +left to right direction + +dfd_tb("Device ") { + rectangle "Application" as caller #PSAMidGray + interface "**Secure Storage API**" as api #PSAGreen + dfd_tb($label="Platform Root of Trust") { + rectangle "Storage service" as service #PSAMidBlue + } + dfd_tb($label="Replay-Protected\nMemory Block") { + database "Storage medium" as store #PSALightGray + } +} + +caller -d- api +api -d-> service : DF1 +service <-d-> store : DF4 + +@enduml diff --git a/doc/storage/figure/dm-authorized.svg b/doc/storage/figure/dm-authorized.svg index 44032111..f1334af6 100644 --- a/doc/storage/figure/dm-authorized.svg +++ b/doc/storage/figure/dm-authorized.svg @@ -1 +1 @@ -«Device»«trust boundary»Platform Root of Trust«trust boundary»Replay-ProtectedMemory BlockApplicationSecure Storage APIStorage serviceStorage mediumDF1DF4 \ No newline at end of file +«Device»«trust boundary»Platform Root of Trust«trust boundary»Replay-ProtectedMemory BlockApplicationSecure Storage APIStorage serviceStorage mediumDF1DF4 \ No newline at end of file diff --git a/doc/storage/figure/dm-exposed.pdf b/doc/storage/figure/dm-exposed.pdf index 8217b8c3..27bffa84 100644 Binary files a/doc/storage/figure/dm-exposed.pdf and b/doc/storage/figure/dm-exposed.pdf differ diff --git a/doc/storage/figure/dm-exposed.puml b/doc/storage/figure/dm-exposed.puml index c85f66ae..7501975a 100644 --- a/doc/storage/figure/dm-exposed.puml +++ b/doc/storage/figure/dm-exposed.puml @@ -1,29 +1,29 @@ ' SPDX-FileCopyrightText: Copyright 2023 Arm Limited and/or its affiliates -' SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license - -@startuml - -!include atg-spec.pumh -!include atg-dataflow.pumh - -skinparam RectangleborderThickness 0 -skinparam RectanglefontColor white -skinparam DatabaseBorderColor #ArmMidGray -skinparam InterfaceBorderColor #ArmMidGray - -left to right direction - -dfd_tb("Device ") { - rectangle "Application" as caller #ArmMidGray - interface "**Secure Storage API**" as api #ArmGreen - dfd_tb($label="Platform Root of Trust") { - rectangle "Storage service" as service #ArmMidBlue - } - database "Storage medium" as store #ArmLightGray -} - -caller -d- api -api -d-> service : DF1 -service <-d-> store : DF3 - -@enduml +' SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +@startuml + +!include psa-spec.pumh +!include psa-dataflow.pumh + +skinparam RectangleborderThickness 0 +skinparam RectanglefontColor white +skinparam DatabaseBorderColor #PSAMidGray +skinparam InterfaceBorderColor #PSAMidGray + +left to right direction + +dfd_tb("Device ") { + rectangle "Application" as caller #PSAMidGray + interface "**Secure Storage API**" as api #PSAGreen + dfd_tb($label="Platform Root of Trust") { + rectangle "Storage service" as service #PSAMidBlue + } + database "Storage medium" as store #PSALightGray +} + +caller -d- api +api -d-> service : DF1 +service <-d-> store : DF3 + +@enduml diff --git a/doc/storage/figure/dm-exposed.svg b/doc/storage/figure/dm-exposed.svg index 8dad9896..10aac56d 100644 --- a/doc/storage/figure/dm-exposed.svg +++ b/doc/storage/figure/dm-exposed.svg @@ -1 +1 @@ -«Device»«trust boundary»Platform Root of TrustApplicationSecure Storage APIStorage mediumStorage serviceDF1DF3 \ No newline at end of file +«Device»«trust boundary»Platform Root of TrustApplicationSecure Storage APIStorage mediumStorage serviceDF1DF3 \ No newline at end of file diff --git a/doc/storage/figure/dm-protected.pdf b/doc/storage/figure/dm-protected.pdf index e8eefca8..0cc0a00c 100644 Binary files a/doc/storage/figure/dm-protected.pdf and b/doc/storage/figure/dm-protected.pdf differ diff --git a/doc/storage/figure/dm-protected.puml b/doc/storage/figure/dm-protected.puml index e2b3a578..49a33f63 100644 --- a/doc/storage/figure/dm-protected.puml +++ b/doc/storage/figure/dm-protected.puml @@ -1,29 +1,29 @@ ' SPDX-FileCopyrightText: Copyright 2023 Arm Limited and/or its affiliates -' SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license - -@startuml - -!include atg-spec.pumh -!include atg-dataflow.pumh - -skinparam RectangleborderThickness 0 -skinparam RectanglefontColor white -skinparam DatabaseBorderColor #ArmMidGray -skinparam InterfaceBorderColor #ArmMidGray - -left to right direction - -dfd_tb("Device ") { - rectangle "Application" as caller #ArmMidGray - interface "**Secure Storage API**" as api #ArmGreen - dfd_tb($label="Platform Root of Trust") { - rectangle "Storage\nservice" as service #ArmMidBlue - database "Storage medium" as store #ArmLightGray - } -} - -caller -d- api -api -d-> service : DF1 -service <--> store : DF2 - -@enduml +' SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +@startuml + +!include psa-spec.pumh +!include psa-dataflow.pumh + +skinparam RectangleborderThickness 0 +skinparam RectanglefontColor white +skinparam DatabaseBorderColor #PSAMidGray +skinparam InterfaceBorderColor #PSAMidGray + +left to right direction + +dfd_tb("Device ") { + rectangle "Application" as caller #PSAMidGray + interface "**Secure Storage API**" as api #PSAGreen + dfd_tb($label="Platform Root of Trust") { + rectangle "Storage\nservice" as service #PSAMidBlue + database "Storage medium" as store #PSALightGray + } +} + +caller -d- api +api -d-> service : DF1 +service <--> store : DF2 + +@enduml diff --git a/doc/storage/figure/dm-protected.svg b/doc/storage/figure/dm-protected.svg index a80b492b..30fa4558 100644 --- a/doc/storage/figure/dm-protected.svg +++ b/doc/storage/figure/dm-protected.svg @@ -1 +1 @@ -«Device»«trust boundary»Platform Root of TrustApplicationSecure Storage APIStorageserviceStorage mediumDF1DF2 \ No newline at end of file +«Device»«trust boundary»Platform Root of TrustApplicationSecure Storage APIStorageserviceStorage mediumDF1DF2 \ No newline at end of file diff --git a/doc/storage/figure/dm-secure-link.pdf b/doc/storage/figure/dm-secure-link.pdf index 4367dbf6..8da0606c 100644 Binary files a/doc/storage/figure/dm-secure-link.pdf and b/doc/storage/figure/dm-secure-link.pdf differ diff --git a/doc/storage/figure/dm-secure-link.puml b/doc/storage/figure/dm-secure-link.puml index f9096ed3..fd21f993 100644 --- a/doc/storage/figure/dm-secure-link.puml +++ b/doc/storage/figure/dm-secure-link.puml @@ -1,31 +1,31 @@ ' SPDX-FileCopyrightText: Copyright 2023 Arm Limited and/or its affiliates -' SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license - -@startuml - -!include atg-spec.pumh -!include atg-dataflow.pumh - -skinparam RectangleborderThickness 0 -skinparam RectanglefontColor white -skinparam DatabaseBorderColor #ArmMidGray -skinparam InterfaceBorderColor #ArmMidGray - -left to right direction - -dfd_tb("Device ") { - rectangle "Application" as caller #ArmMidGray - interface "**Secure Storage API**" as api #ArmGreen - dfd_tb($label="Platform Root of Trust") { - rectangle "Storage service" as service #ArmMidBlue - } - dfd_tb($label="Secure Element") { - database "Storage medium" as store #ArmLightGray - } -} - -caller -d- api -api -d-> service : DF1 -service <-d-> store : DF5 - -@enduml +' SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +@startuml + +!include psa-spec.pumh +!include psa-dataflow.pumh + +skinparam RectangleborderThickness 0 +skinparam RectanglefontColor white +skinparam DatabaseBorderColor #PSAMidGray +skinparam InterfaceBorderColor #PSAMidGray + +left to right direction + +dfd_tb("Device ") { + rectangle "Application" as caller #PSAMidGray + interface "**Secure Storage API**" as api #PSAGreen + dfd_tb($label="Platform Root of Trust") { + rectangle "Storage service" as service #PSAMidBlue + } + dfd_tb($label="Secure Element") { + database "Storage medium" as store #PSALightGray + } +} + +caller -d- api +api -d-> service : DF1 +service <-d-> store : DF5 + +@enduml diff --git a/doc/storage/figure/dm-secure-link.svg b/doc/storage/figure/dm-secure-link.svg index 9324643d..4e76ea0e 100644 --- a/doc/storage/figure/dm-secure-link.svg +++ b/doc/storage/figure/dm-secure-link.svg @@ -1 +1 @@ -«Device»«trust boundary»Platform Root of Trust«trust boundary»Secure ElementApplicationSecure Storage APIStorage serviceStorage mediumDF1DF5 \ No newline at end of file +«Device»«trust boundary»Platform Root of Trust«trust boundary»Secure ElementApplicationSecure Storage APIStorage serviceStorage mediumDF1DF5 \ No newline at end of file diff --git a/doc/storage/figure/lifecycle.pdf b/doc/storage/figure/lifecycle.pdf index 66927b7a..48c3d520 100644 Binary files a/doc/storage/figure/lifecycle.pdf and b/doc/storage/figure/lifecycle.pdf differ diff --git a/doc/storage/figure/lifecycle.puml b/doc/storage/figure/lifecycle.puml index ff5bc138..160264b4 100644 --- a/doc/storage/figure/lifecycle.puml +++ b/doc/storage/figure/lifecycle.puml @@ -1,39 +1,39 @@ ' SPDX-FileCopyrightText: Copyright 2023 Arm Limited and/or its affiliates -' SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license - -@startuml - -!include atg-spec.pumh -!include atg-lifecycle.pumh - -stakeholder "SiP and OEM" as n1 -stakeholder "SiP and/or OEM" as n2 -stakeholder "[everybody]" as n3 -stakeholder_skip as n4 -stakeholder "SiP, OEM,\nand Owner" as n5 - -lifecycle_phase "Manufacturing" as r1 { - lifecycle_state "System\nmanufacturing\nand initialization" as lc1 - lifecycle_state "Provision of\nRoot of Trust\nsecrets" as lc2 -} -lifecycle_phase "Operational" as r3 { - lifecycle_state "Boot" as lc3 - lifecycle_state "Secure operation" as lc4 -} -lifecycle_phase "End of life" as r5 { - lifecycle_state "Return to\nManufacturer" as lc5 -} - -lc1 --> lc2 -lc2 --> lc3 -lc3 --> lc4 -lc4 --> lc5 - -n1 -[hidden]- n2 -n2 -[hidden]- n3 -n3 -[hidden]- n4 -n4 -[hidden]- n5 - -lc1 -[hidden] n1 - -@enduml +' SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +@startuml + +!include psa-spec.pumh +!include psa-lifecycle.pumh + +stakeholder "SiP and OEM" as n1 +stakeholder "SiP and/or OEM" as n2 +stakeholder "[everybody]" as n3 +stakeholder_skip as n4 +stakeholder "SiP, OEM,\nand Owner" as n5 + +lifecycle_phase "Manufacturing" as r1 { + lifecycle_state "System\nmanufacturing\nand initialization" as lc1 + lifecycle_state "Provision of\nRoot of Trust\nsecrets" as lc2 +} +lifecycle_phase "Operational" as r3 { + lifecycle_state "Boot" as lc3 + lifecycle_state "Secure operation" as lc4 +} +lifecycle_phase "End of life" as r5 { + lifecycle_state "Return to\nManufacturer" as lc5 +} + +lc1 --> lc2 +lc2 --> lc3 +lc3 --> lc4 +lc4 --> lc5 + +n1 -[hidden]- n2 +n2 -[hidden]- n3 +n3 -[hidden]- n4 +n4 -[hidden]- n5 + +lc1 -[hidden] n1 + +@enduml diff --git a/doc/storage/figure/lifecycle.svg b/doc/storage/figure/lifecycle.svg index 0b79fe6f..4a2b5d92 100644 --- a/doc/storage/figure/lifecycle.svg +++ b/doc/storage/figure/lifecycle.svg @@ -1 +1 @@ -ManufacturingOperationalEnd of lifeSystemmanufacturingand initializationProvision ofRoot of TrustsecretsBootSecure operationReturn toManufacturerSiP and OEMSiP and/or OEM[everybody]SiP, OEM,and Owner \ No newline at end of file +ManufacturingOperationalEnd of lifeSystemmanufacturingand initializationProvision ofRoot of TrustsecretsBootSecure operationReturn toManufacturerSiP and OEMSiP and/or OEM[everybody]SiP, OEM,and Owner \ No newline at end of file diff --git a/doc/storage/figure/storage.pdf b/doc/storage/figure/storage.pdf index b0df9918..f2dc2ca4 100644 Binary files a/doc/storage/figure/storage.pdf and b/doc/storage/figure/storage.pdf differ diff --git a/doc/storage/figure/storage.puml b/doc/storage/figure/storage.puml index 0947d76a..f48add93 100644 --- a/doc/storage/figure/storage.puml +++ b/doc/storage/figure/storage.puml @@ -2,7 +2,7 @@ ' SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license @startuml -!include atg-spec.pumh +!include psa-spec.pumh participant "Application" as app box "Platform Root of Trust" #E0E0E0 diff --git a/doc/storage/figure/storage.svg b/doc/storage/figure/storage.svg index 8643f4de..740a4b87 100644 --- a/doc/storage/figure/storage.svg +++ b/doc/storage/figure/storage.svg @@ -1 +1 @@ -Platform Root of TrustApplicationCryptographyInternal TrustedApplicationCryptographyserviceInternal TrustedStorage servicepsa_import_key(key_slot, key_material)psa_its_set(partition_id<<32 | key_identifier, key_material)pass/failpass/fail \ No newline at end of file +Platform Root of TrustApplicationCryptographyInternal TrustedApplicationCryptographyserviceInternal TrustedStorage servicepsa_import_key(key_slot, key_material)psa_its_set(partition_id<<32 | key_identifier, key_material)pass/failpass/fail \ No newline at end of file diff --git a/doc/storage/index.rst b/doc/storage/index.rst index d1c878e7..10c1a824 100644 --- a/doc/storage/index.rst +++ b/doc/storage/index.rst @@ -1,19 +1,11 @@ -.. SPDX-FileCopyrightText: Copyright 2018-2019, 2022-2024 Arm Limited and/or its affiliates +.. SPDX-FileCopyrightText: Copyright 2018-2019, 2022-2024, 2026 Arm Limited and/or its affiliates .. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license .. title:: - .. abstract:: - - This document is part of the PSA Certified API specifications. It defines interfaces to provide secure storage services. - -.. front-matter:: - - about - .. maintoc:: - overview/intro + about/about overview/architecture overview/requirements overview/operation diff --git a/doc/storage/overview/architecture.rst b/doc/storage/overview/architecture.rst index f6b7bf7b..edae69d8 100644 --- a/doc/storage/overview/architecture.rst +++ b/doc/storage/overview/architecture.rst @@ -66,7 +66,7 @@ UIDs ``uids`` in the |API| are defined as ``uint64_t``. This is expected to be larger than would be used on any system. This large namespace is chosen to allow a :term:`Root of Trust Service` to easily manage assets on behalf of other services. -For example, consider a cryptography service running as a RoT Service. When a service running in a :term:`Secure Partition` requests key storage from the cryptography service, the cryptography service can concatenate a numerical identity of the requesting partition (for example, a ``int32_t`` in the :cite-title:`PSA-FFM`) with the key identifier (for example, a ``uint32_t`` in the :cite-title:`PSA-CRYPT`) to generate the ``uid`` of the Internal Trusted Storage entry for the key. This allows the cryptography service to easily manage isolation between the key namespaces of its various clients. +For example, consider a cryptography service running as a RoT Service. When a service running in a :term:`Secure Partition` requests key storage from the cryptography service, the cryptography service can concatenate a numerical identity of the requesting partition (for example, a ``int32_t`` in the :cite-title:`PSA FFM`) with the key identifier (for example, a ``uint32_t`` in the :cite-title:`PSA CRYPT`) to generate the ``uid`` of the Internal Trusted Storage entry for the key. This allows the cryptography service to easily manage isolation between the key namespaces of its various clients. Requirements for ``uid``: diff --git a/doc/storage/overview/intro.rst b/doc/storage/overview/intro.rst deleted file mode 100644 index 0289a772..00000000 --- a/doc/storage/overview/intro.rst +++ /dev/null @@ -1,29 +0,0 @@ -.. SPDX-FileCopyrightText: Copyright 2018-2019, 2022,2025 Arm Limited and/or its affiliates -.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license - -.. _intro: - -Introduction -============ - -About Platform Security Architecture ------------------------------------- - -This document is one of a set of resources provided by Arm that can help organizations develop products that meet the security requirements of GlobalPlatform's PSA Certified evaluation scheme on Arm-based platforms. The PSA Certified scheme provides a framework and methodology that helps silicon manufacturers, system software providers and OEMs to develop more secure products. Arm resources that support PSA Certified range from threat models, standard architectures that simplify development and increase portability, and open-source partnerships that provide ready-to-use software. You can read more about PSA Certified here at :url:`www.psacertified.org` and find more Arm resources here at :url:`developer.arm.com/platform-security-resources` and :url:`www.trustedfirmware.org`. - -About the |API| ---------------- - -The interface described in this document is a PSA Certified API, that provides key/value storage interfaces for use with device-protected storage. The |API| describes two interfaces for storage: - -.. csv-table:: - :widths: 3 7 - - Internal Trusted Storage API, An interface for storage provided by the :term:`Platform Root of Trust` (PRoT). - Protected Storage API, An interface for external protected storage. - -The Internal Trusted Storage API must be implemented in the PRoT as described in the :cite-title:`PSM` specification. - -If there are no :term:`Application Root of Trust` (ARoT) services that rely on it, the Protected Storage API can be implemented in the :term:`NSPE`. Otherwise, the Protected Storage API must be implemented in an ARoT within the :term:`SPE`. - -You can find additional resources relating to the |API| here at :url:`arm-software.github.io/psa-api/storage`, and find other PSA Certified APIs here at :url:`arm-software.github.io/psa-api`. diff --git a/doc/storage/overview/operation.rst b/doc/storage/overview/operation.rst index 0558fda4..48be5c97 100644 --- a/doc/storage/overview/operation.rst +++ b/doc/storage/overview/operation.rst @@ -11,7 +11,7 @@ The Internal Trusted Storage service that implements the Internal Trusted Storag Internally the Internal Trusted Storage service should be designed such that one partition cannot access the data owned by another partition. The method of doing this is not specified here, but one method would be to store metadata with the data indicating the partition that owns it. -:numref:`fig-crypto-storage` provides a simple example of how an Internal Trusted Storage service can be used by a service that implements :cite-title:`PSA-CRYPT` to secure keystore material. This is illustrative and not prescriptive. +:numref:`fig-crypto-storage` provides a simple example of how an Internal Trusted Storage service can be used by a service that implements :cite-title:`PSA CRYPT` to secure keystore material. This is illustrative and not prescriptive. .. figure:: /figure/storage.* :name: fig-crypto-storage diff --git a/doc/storage/overview/requirements.rst b/doc/storage/overview/requirements.rst index 6bb36b4e..b5af72ee 100644 --- a/doc/storage/overview/requirements.rst +++ b/doc/storage/overview/requirements.rst @@ -41,4 +41,4 @@ Internal Trusted Storage requirements 14. The `PSA_STORAGE_FLAG_WRITE_ONCE` must be enforced when the Root of Trust Lifecycle state of the device is ``SECURED`` or ``NON_PSA_ROT_DEBUG``. It must not be enforced when the device is in the ``PSA_ROT_PROVISIONING`` state. 15. The creation of a ``uid`` with value ``0`` (zero) must be treated as an error. -The lifecycle states are described in :cite-title:`PSM` and :cite-title:`PSA-FFM`. +The lifecycle states are described in :cite-title:`PSM` and :cite-title:`PSA FFM`. diff --git a/doc/storage/pyproject.toml b/doc/storage/pyproject.toml new file mode 100644 index 00000000..52de3a0e --- /dev/null +++ b/doc/storage/pyproject.toml @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: Copyright 2026 Arm Limited and/or its affiliates +# SPDX-License-Identifier: Apache-2.0 + +[tool.esbonio] diff --git a/tools/atg-sphinx-conf.py b/tools/atg-sphinx-conf.py new file mode 100644 index 00000000..f3086d8b --- /dev/null +++ b/tools/atg-sphinx-conf.py @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +# SPDX-License-Identifier: Apache-2.0 + +# Compatibility wrapper for older specification sources that still execute +# atg-sphinx-conf.py from the former atg-sphinx-spec tool. + +import os + +psa_api_tool_path = (os.environ.get('PSA_API_TOOL') or + os.environ.get('ATG_SPHINX_SPEC') or + globals().get('atg_sphinx_spec_dir')) + +if not psa_api_tool_path: + raise RuntimeError('PSA_API_TOOL or ATG_SPHINX_SPEC must point to psa-api-tool') + +exec(compile(open(os.path.join(psa_api_tool_path, 'psa-api-conf.py'), + encoding='utf-8').read(), + 'psa-api-conf.py', 'exec')) diff --git a/tools/docs/psa-api-tool-notes.md b/tools/docs/psa-api-tool-notes.md new file mode 100644 index 00000000..0d0d7478 --- /dev/null +++ b/tools/docs/psa-api-tool-notes.md @@ -0,0 +1,2516 @@ + + +# psa-api-tool Notes + +This note is a lightweight contributor and editor guide for the `psa-api-tool` Sphinx +extension and build support. + +It is intended to capture the practical behavior of the tool as used in PSA +specification sources. It is written for both human editors and automated editing +agents, so headings, directive names, role names, and examples should remain explicit +and easy to search. + +This is not a full implementation reference. When behavior is unclear, verify against +`psa-api-tool.py`, `psa-api-conf.py`, the shared `make` file, and the template files. + +## Audience and Scope + +These notes describe: + +- what each custom directive or role is for +- the important arguments and options +- where it can be used +- shared PSA API source conventions +- known limitations or gotchas +- minimal working examples + +This note currently focuses on the parts of `psa-api-tool` that are needed to edit and +extend specification source text effectively, especially: + +- API and manifest definition directives +- release metadata inputs +- terms/glossary definitions +- references and citation roles + +It also records shared source conventions used across PSA API specifications. Individual +specification repositories can add narrower local rules where needed. + +Broader setup and build instructions are in `using-psa-api-tool.md`. This includes +dependency notes, repository layout, configuring document metadata in `conf.py`, and +running common build targets. + +## Guide Map + +Use these sections as the usual entry points: + +- `Shared Source Editing Conventions` for punctuation, wrapping, recommendation wording, + graphics, API definition layout, generated headers, admonitions, and inline code + style. +- `Directive Reference` for custom and modified directives, grouped by typical authoring + context. +- `Role Reference` for custom roles and modified reference behavior. +- `Security Risk Assessment Directives and Roles` for SRA-specific structured threat + content. + +## Shared Source Editing Conventions + +These conventions are intended for PSA API specifications that use `psa-api-tool`. They +should be treated as shared conventions unless a consuming repository explicitly says +otherwise. + +### Plain source punctuation + +Use plain ASCII single and double quote characters in specification sources. Sphinx +converts quotes and apostrophes to the appropriate typographic characters when rendering +HTML and LaTeX output, so source files should not use Unicode curly quotation marks such +as `‘`, `’`, `“`, or `”`. + +Use ASCII source forms for dashes when typographic dashes are intended in the rendered +output. Sphinx converts `--` to an en-dash and `---` to an em-dash. Use these source +forms instead of Unicode dash characters. For example, use an em-dash for an explanatory +aside: + +```rst +The value is private to the caller --- it cannot be read by another component. +``` + +Use normal ASCII hyphens for hyphenated terms and ASCII minus signs in code, numeric +ranges, and literal values. + +### American English spelling + +Use American English spelling in specification sources. For example, use `behavior`, +`initialize`, `optimization`, and `synchronization`. + +### Source line wrapping and indentation + +These conventions apply to all reStructuredText specification sources, including `.rst` +files and extensionless included source fragments such as `terms`, `references`, and +`releases`. + +Use one logical paragraph per source line. Let the editor wrap long source lines for +display. This keeps the source structure aligned with the document structure, avoids +inconsistent wrapping in files edited with different window widths, and matches the +current style used in other PSA API specifications. + +Keep block indentation consistent within a source file. Use three spaces for directive +bodies, nested directive content, list continuation text, and other indented +reStructuredText blocks. + +Use the same three-space convention for `.. list-table::` directives. The directive +options and outer row list are indented by three spaces, nested cell list items are +indented by six spaces, and table cell continuation text is indented by nine spaces. + +Use bullet-list markers with two spaces after the marker, for example `* List item`. +This means the text starts after three source characters and aligns naturally with +continuation lines that use the three-space indentation convention. Enumerated list +markers already occupy three source characters when they use a single-digit number, an +alphabetic marker, or automatic numbering, for example `1. List item`, `a. List item`, +or `#. List item`. + +For nested bullet lists, use `-` as the inner list marker under an outer `*` list. +Indent the nested marker by three spaces and keep the same two spaces after the marker, +for example ` - Nested item`. The same marker convention is used in `.. list-table::` +row and cell lists. + +When making semantic changes, do not reformat unrelated paragraphs or indentation in the +same patch. If a source file has mixed wrapping or indentation conventions, clean it up +in a separate mechanical formatting pass so that review can distinguish formatting churn +from specification changes. + +### Recommendation wording + +When documenting recommended behavior or design choices, use neutral specification +wording rather than organization-voiced wording. + +Prefer: + +- `It is recommended that ...` +- `The following behavior is recommended:` + +Avoid: + +- `Arm recommends that ...` +- `We recommend that ...` + +This keeps advisory specification text independent of a motivated speaker, while still +distinguishing recommendations from normative requirements such as `must`, `must not`, +`shall`, and `shall not`. + +### Rendered graphics + +Rendered graphics are normally checked in to specification repositories. This means that +editors who only modify text can build the documents without installing every graphics +rendering tool. + +When modifying graphics sources, update the rendered assets at the same time. For +example, changes to `.svg` figures must keep the corresponding `.pdf` rendering up to +date for PDF builds. The `images` make target regenerates graphics derived from `.json`, +`.puml`, and `.svg` sources when the required tools are available. + +### C API element definitions + +The `.. macro::`, `.. typedef::`, `.. struct::`, `.. function::`, and `.. enum::` +directives are top-level directives that define C API elements. This section describes +common aspects of these directives, and best practices for using them. + +Details for each directive are provided in the Directive Reference. + +#### Rendering + +In the current tooling, each API element directive forms a section node within the +document model, and the API element name forms the title for the section. As a result, +an API element defined within a heading level 3 section will be a level 4 section, an +API element defined within a heading level 2 section will be a level 3 section. The +effect is that the heading format for an API element depends on the enclosing section +level. + +For consistency in a specification, it is important to have every API element defined at +the same level in the document hierarchy. Existing PSA API specifications commonly use +level 4, the first level that does not include a section number in the heading. This +occasionally requires creative chapter structuring so that this is achieved. + +#### Standard options + +These options are available for all C API element directives, but are used rarely, only +when required for the individual API element. + +- `:header:` (optional) - see the header file section below for details. +- `:guard:` (optional) - this adds an optional #ifdef guard around the API element + definition in the header file. +- `:comment:` (optional) - specify a comment text to include in the generated header + before the API element definition. +- `:naked:` (optional) - do not include this API element in any header file. + +#### Typical layout of element definitions + +After the element directive and any options, which can include a definition for macros, +the following is a recommended ordering for API definitions: + +- Summary directive. +- Sub-element directives, such as parameters for a function or macro-like function; + fields for a structure; or values for an enumeration. +- Return directive. +- Return value directives for a function or macro-like function. +- Description, as text within the element directive. + +If a specification or a set of related API elements has shared subsections in the +description, add them as `.. subsection::` directives. Place them consistently in the +source to aid maintenance. Examples include the 'Key format' sections in the Crypto API +key type definitions and the 'Compatible key types' sections in the Crypto API algorithm +definitions. + +When rendered, the tool fixes the ordering of the API definition (to match the list +above), then any subsections labeled `:top:`, then the general description, and finally +any subsections not labeled `:top:`. The recommended layout here matches that to +facilitate easier editing. + +Optional: it is possible to specify a document-wide ordering of return values (typically +for error codes) in the `doc_info` dictionary, to force consistency in the output +without demanding the same in the source material. This is used for the larger API +specifications, such as the Crypto API. + +#### Using `summary` directives + +Each C API element directive should have a `.. summary::` directive with a short +description of the API. The first sentence of the summary is used when generating +Doxygen-enhanced reference header file output with the `headers` make format. + +#### Placement of `.. versionadded::` directives + +After testing, the best placement for these in API element descriptions is at the end of +the `summary` directive. For example: + +```rst +.. macro:: EXAMPLE + + .. summary:: An example macro definition. + + .. versionadded:: 2.3 + + More content. +``` + +The same is true for the `.. versionchanged::`, `.. deprecated::`, and `.. +versionremoved::` directives. + +Shared PSA API convention for API definitions: + +- Use `.. versionadded::` only for new API elements. +- Use `.. versionchanged::` for existing API elements whose behavior, constraints, or + meaning changed materially. +- Use `.. deprecated::` for existing API elements that remain specified but are + deprecated. +- Omit the directive body when the marker is self-explanatory. +- If a body is useful, use at most one short sentence. +- Keep rationale, migration guidance, and fuller explanation in the normal API prose + rather than in the version directive body. +- Do not use version markup just because a version-valued macro or function now reports + the newer document version. Reserve it for API evolution that a reader needs called + out explicitly. + +### Generated header files + +The tooling builds API element definitions from the directive-based descriptions in the +source specification. This ensures that element definitions are always consistent +between the detailed description, the API signature, and the content of any generated +embedded or external header file. + +#### Associating an API element with a named header file + +The tooling supports different types of specification project. + +- If a `header` attribute is specified in the `conf.py` `doc_info` dictionary, this is + the default header for an API element. + +- If a documentation source file uses a `.. header::` directive, this defines the header + to associate with any element definitions that follow it. This directive can be used + multiple times in a single source file for different headers. + +- A single instance of the `.. header::` directive for each header file can also be used + to specify additional information about a header file, such as inclusion of a license + or copyright preamble and header guard inclusion. See the description of the `.. + header::` directive for details. + +- If an API element uses the `:header:` option, this overrides any default or directive + setting. + +Guidance: + +- For a single header project, use the `doc_info['header']` attribute. +- For a multi-header project, use the `.. header::` directive as required. +- For the odd API element that lives in a different file, use the `:header:` option. + +#### Use of generated headers + +Generated headers are used in three ways: + +1. Included inline in the specification output. This uses the `.. insert-header::` + directive, and produces an in-sequence, unannotated, cross-referenced source listing + of the canonical header. + +2. Output using the `api-db` build format, which is used by the `api-db`, `api-diff`, + and `api-update` make formats to create, review, and maintain a baseline API + definition to enable checks that changes to the specification sources only introduce + expected changes to the API. This format has the elements alphabetically sorted and + unannotated. + + By default, the `api-*` make targets use or update a set of headers in the document's + `api.db/` folder. + +3. Output using the `headers` build format, which can be used to create + Doxygen-annotated, in-sequence, copyright-commented canonical header files for + inclusion in a project repository. This output is useful for implementation + developers because IDEs can use the annotations for API tooltips and code completion. + The level of Doxygen annotation is controlled by the `header_doxygen` configuration + attribute in `doc_info`. + +#### API element sequencing within header files + +For the `.. insert-header::` directive and the `headers` build format, the API elements +appear in the header file in the order that they are defined in the source files. When +multiple source files provide definitions for the same header file, the `:seq:` option +should be used in a `.. header::` directive to ensure that the definitions from +different source files appear in the intended order in the header file. + +In contrast, the `api-db` build format used by `api-diff` and `api-update` normalizes +the output by API element identity, so it is resistant to documentation refactoring and +to incidental variation in Sphinx partial-build ordering. This is why changes to source +ordering often affect the inserted header listings and `headers` output, but do not +affect the `api.db` baseline. + +The main practical use of `:seq:` is therefore for generated header listings and +`headers` output when a single header is assembled from multiple source files. In +specifications where each standard header has a single source location, `:seq:` is +generally not needed. In larger APIs such as the Crypto API, where many source files +contribute to one header, `:seq:` is important to keep the generated header order stable +and intentional. + +### Using callouts/admonitions + +Many of the docutils/Sphinx admonitions are used within the specifications. Here are the +typical uses: + +- `.. note::` - informative material for a developer that is related to the current + text, but is not necessary for normal use of it. +- `.. admonition:: Implementation note` - informative material for an implementer of the + specification, often providing options or recommendations. This is just a titled + generic admonition element. +- `.. warning::` - call out an issue that presents a risk for the implementer or user of + an API. Use sparingly. +- `.. todo::` - identify unfinished work in the specification. These should be resolved + prior to publishing a specification. By default, these are rendered when the document + has a non-zero draft revision, but can be enabled explicitly by adding `'todo'` to the + `doc_info['include_content']` attribute. +- `.. rationale::` - provide justification for a design decision. By default, these are + rendered when the document has a non-zero draft revision, but can be enabled + explicitly by adding `'rationale'` to the `doc_info['include_content']` attribute. +- `.. comment::` - provide commentary related to documentation content. Most useful for + including notes for reviewers of the rendered documents. By default, these are not + rendered in a build, but can be overridden by adding `'comment'` to the + `doc_info['include_content']` attribute. + +Admonitions can also be included in the bodies of API element directives, subsection +directives, or sub-element directives. Use them sparingly inside API entries so they +don't overwhelm the normative flow. + +### Formatting inline code/monospace text + +Quick rules-of-thumb: + +- Use ``text`` for plain literal monospace +- Use `text` for the default reference role +- Use the `:code:` role for code-like text that should hyperlink defined identifiers + when possible + +In more detail: + +- For plain literal monospace text or code fragments, use the standard reStructuredText + double backticks: ``monospace text``. +- For single API elements or manifest attributes that are defined anywhere in the Sphinx + document, use the default reference role: `MACRO` or `function()`. This renders as + monospace code, hyperlinked to the definition of the element/attribute. PSA + documentation convention includes the function parentheses, but these are optional. +- For code that should link to API elements or manifest identifiers when possible, use + the `:code:` role: :code:`foo(MACRO,1)` or :code:`<= MAX_VAL`. This renders as + monospace code, hyperlinking every identifier or attribute that is present in the + text. +- The `:code:` role is also useful for identifiers that are moving to or from another + specification, as these will render as links when possible, otherwise as plain code. + +## Directive Reference + +Documentation conventions for this reference: + +- document the practical use of the directive as seen in these spec sources, rather than + trying to reverse engineer every implementation detail +- prefer minimal examples copied or adapted from real specification usage +- group document assembly directives by authoring context, so editors can find the + directives relevant to the file they are editing + +Use one section per directive. Keep examples minimal. + +Recommended format: + +- Purpose +- Syntax +- Common options +- Placement rules +- Output/effect +- Example +- Gotchas + +### API documentation directives + +#### `.. header::` + +Purpose: + +Specify the header file to associate the following API elements with. + +Syntax: + +The header file name is the directive argument. The directive body (optional) provides +additional content (e.g. comments) to include after any copyright or license text. + +```rst +.. header:: psa/example + :copyright: Copyright notice + :license: Source license + :c++: + :guard: + :system-include: stddef.h stdint.h + :include: psa/error.h + + /* Optional comment block + */ +``` + +Common options: + +All options are optional. + +- `:copyright:` - a copyright notice, included in the `headers` format build. +- `:license:` - an SPDX license identifier, included in the `headers` format build. +- `:c++:` - add preprocessing directives to be able to include the header in a C++ + project. +- `:guard:` - add preprocessing directives to guard against double-inclusion of the + header file. +- `:system-include:` - list of system-include files to add to the header. +- `:include:` - list of project include files to add to the header. +- `:seq:` - a numerical sequence number for the set of API elements that follow. This + enables definitions across multiple sources to be output in a defined order. + +Apart from `:seq:`, these options can only be provided on a single instance of the `.. +header::` directive for each header file within the document sources. + +Placement rules: + +Anywhere in a .rst source, outside of an API element definition. + +Output/effect: + +Associates all following API definitions with the named header, unless they provide a +`:header:` override option. Defines the order in which API elements are included in a +header file. Specifies additional material to be used when generating the header file. + +Example: + +```rst +.. header:: psa/crypto + :seq: 10 + :copyright: Copyright 2026 Example Publisher + :license: Apache-2.0 + :c++: + :guard: + :system-include: stddef.h stdint.h + :include: psa/error.h + + /* This file is a reference template for implementation of the + * PSA Certified Crypto API v1.5 + */ +``` + +Gotchas: + +When using the copyright option, license option, or including a version in the comments; +these are not affected by changing the document configuration and must be edited to +match the document setup. + +#### `.. insert-header::` + +Purpose: + +Insert the named header into the document. + +Syntax: + +```rst +.. insert-header:: psa/example +``` + +Placement rules: + +None. Current practice is to use this in an appendix. + +This directive is processed after all document sources have been parsed - ensuring that +the inserted header is always consistent with the API definitions in the document. + +Output/effect: + +The named header is generated as a source listing, and automatically cross-references +all defined API elements. + +Example: + +```rst +.. insert-header:: psa/client +``` + +#### `.. macro::` + +Purpose: + +Define a macro API element. + +For function-like macros, include one or more parameter definitions, and an optional +return description as part of the directive body. + +Syntax: + +```rst +.. macro:: PSA_EXAMPLE + :definition: (0u) + + .. summary:: Summary text. + + .. param:: parameter_name + Parameter description. + .. return:: + Return value description. + + Macro description. +``` + +The `.. macro::` directive argument is the name of the macro. The optional macro +definition is provided in the `:definition:` option. For a function-like macro: + +- The parameter names are taken from `.. param::` directives in the body, in the order + in the .rst file. +- Optionally, `.. return::` and `.. retval::` directives can be used to describe the + expected output. + +Common options: + +- `:definition:` (optional) - provide the macro definition. +- `:api-version: ` (optional) - define the macro using the document version + (from conf.py). `type` is one of `major`, `minor`, or `hex` which results in the + macro definition being the major version, minor version, or a 16-bit + `(major << 8) | minor` value respectively. This option cannot be used at the same + time as `:definition:`. + +Also, see the standard API element options. + +Placement rules: + +Anywhere in a document section, but see the note about Rendering of C API element +definitions above. + +Output/effect: + +Creates a macro definition section in the document, and adds the macro to the generated +API declarations. + +If no definition is provided, the default comment definition of `/* ... */` is used. + +Example: + +```rst +.. macro:: PSA_VERSION_NONE + :definition: (0u) + + .. summary:: This is the return value from `psa_version()` if the requested RoT + Service is not present. +``` + +Gotchas: + +The tool still permits legacy use of having the macro definition as additional lines in +the directive argument. Current best practice is to have only the name in the directive +argument, and include any definition in the `:definition:` option. + +To force an empty definition for the macro, use a `:definition:` option with no content. + +#### `.. function::` + +Purpose: + +Define a function or function-pointer API element. + +Provide the parameter definitions, return type, and important return values as part of +the directive body. + +Syntax: + +```rst +.. function:: psa_example + + .. summary:: Summary text. + + .. param:: param_type param_name + Parameter description. + .. return:: return_type + Short description of returned value. + .. retval:: value or value description + Details on specific error code, or return values. + + Function description. +``` + +The `.. function::` directive argument is only the name of the function. The function +parameter types and names are taken from `.. param::` directives in the body, in the +order in the .rst file. The function return type is taken from the `.. return::` +directive in the body. + +Common options: + +- `:type:` - define a function pointer type. Use this for defining callback or + function-pointer types instead of ordinary functions. + +Also, see the standard API element options. + +Placement rules: + +Anywhere in a document section, but see the note about Rendering of C API element +definitions above. + +Output/effect: + +Creates a function or function-type definition section in the document, and adds the +function or function-type to the generated API declarations. + +Example: + +```rst +.. function:: psa_framework_version + + .. summary:: This function retrieves the version of the PSA Framework API that is implemented. + + .. return:: uint32_t +``` + +Gotchas: + +For a void-returning function, the `.. return:: void` directive must be included in the +body, to avoid a warning about a missing return type. + +#### `.. typedef::` + +Purpose: + +Define a type alias. + +This directive can also be used to define incomplete types and incomplete structure +types. + +Syntax: + +```rst +.. typedef:: uint32_t psa_example_t + + .. summary:: Summary text. +``` + +The directive argument is the type definition. It can optionally include the `typedef` +prefix and a trailing `;`. + +To define an incomplete type, which an implementation of the API must fully define, a +comment can be used in the definition. For example: + +```rst +.. typedef:: /* implementation-defined type */ psa_example_t + + .. summary:: Summary text. +``` + +Common options: + +See the standard API element options. + +Placement rules: + +Anywhere in a document section, but see the note about Rendering of C API element +definitions above. + +Output/effect: + +Creates a typedef definition section in the document, and adds the type definition to +the generated API declarations. + +Example: + +```rst +.. typedef:: int32_t psa_handle_t + + .. summary:: This type is used for handles. +``` + +Gotchas: + +Use a `.. function::` directive with the `:type:` option to define a pointer-to-function +type. + +#### `.. struct::` + +Purpose: + +Define a structure or structure type API element. + +Provide the member definitions as part of the directive body. + +Syntax: + +```rst +.. struct:: psa_example + :type: + + .. summary:: Summary text. + + .. field:: uint32_t member + Field description. +``` + +Structure members are declared using the `.. field::` directives in the body, and appear +in the order of definition in the source .rst file. + +Common options: + +- `:type:` - define a typedef for the structure identifier, not just the named `struct`. + +Also, see the standard API element options. + +Placement rules: + +Anywhere in a document section, but see the note about Rendering of C API element +definitions above. + +Output/effect: + +Creates a structure definition section in the document, and adds the definition to the +generated API declarations. + +Example: + +```rst +.. struct:: psa_msg_t + :type: +``` + +Gotchas: + +To define an incomplete structure type, use a `.. typedef::` directive with a commented +structure body. For example: + +```rst +.. typedef:: struct { /* implementation-defined */ } psa_example + + Type description. +``` + +#### `.. enum::` + +Purpose: + +Define an enumeration or enumeration type API element. + +Syntax: + +```rst +.. enum:: psa_example + :type: + + .. summary:: Summary text. + + .. value:: VALUE_1 = 42 + Enumeration value description. +``` + +Enumeration values are declared using the `.. value::` directives in the body, and +appear in the order of definition in the source .rst file. + +Common options: + +- `:type:` - define a typedef for the enumeration identifier, not just the named `enum`. + +Also, see the standard API element options. + +Placement rules: + +Anywhere in a document section, but see the note about Rendering of C API element +definitions above. + +Output/effect: + +Creates an enumeration definition section in the document, and adds the definition to +the generated API declarations. + +Example: + +```rst +.. enum:: psa_operation_mode_t + :type: + + .. value:: sync = 1 + .. value:: async = 2 +``` + +#### `.. attribute::` + +Purpose: + +Define a JSON schema element. + +Syntax: + +```rst +.. attribute:: example_attribute + + Properties: Required. + + Description text. +``` + +Placement rules: + +Anywhere in a document section, but see the note about Rendering of C API element +definitions above. + +Output/effect: + +Generate a JSON attribute definition section in the document. + +JSON attributes do not appear in any generated C header file. However, JSON attributes +can be cross-referenced, as for API identifiers, and will be automatically linked in +inline code and code blocks that specify the `xref` language. + +Example: + +```rst +.. attribute:: psa_framework_version + + Properties: Required. +``` + +Gotchas: + +Although JSON attributes do not share a programming namespace with C API identifiers, +the psa-api-tool currently does not separate these domains when resolving +cross-references. If a C identifier and a JSON attribute have the same name, this will +result in build warnings and can result in incorrect cross reference linkage. + +Shared PSA convention for nested JSON objects: + +When documenting nested manifest objects such as `service`, `irq`, or MMIO region +objects, do not use nested `.. attribute::` directives for the sub-attributes unless the +tooling has been extended to support scoped names. Today, repeated attribute names such +as `name` and `description` would collide. + +Instead: + +- keep the top-level JSON attribute, such as `services` or `irqs`, as the single `.. + attribute::` definition +- structure the body using `.. rubric::` titles for internal grouping +- use `.. container:: apisubitem` with definition-list style content to document nested + object attributes in a compact, API-like layout + +This is a source convention rather than a formal feature of the extension, but it is +stable in practice because `apisubitem` is the same styling hook used internally for API +sub-elements. + +#### `.. summary::` + +Purpose: + +Provide a brief summary of the API element. This is typically a single sentence. + +Syntax: + +```rst +.. summary:: Summary sentence. +``` + +Placement rules: + +Must be nested under an API element directive. + +Output/effect: + +This is the first text within an API element definition section, before the prototype of +the API element. + +The first sentence of the summary is used as the Doxygen `@brief` text in generated +header files, typically used by IDEs for code completion support. + +Example: + +```rst +.. macro:: PSA_FRAMEWORK_VERSION + + .. summary:: The version of the PSA Framework API provided by the included header file. +``` + +Gotchas: + +The preferred place to provide `.. versionadded::` directives is as the last part of the +body of the API element's `.. summary::` directive. + +#### `.. param::` + +Purpose: + +Document a parameter to a function or macro. + +Syntax: + +```rst +.. param:: + Parameter description. +``` + +The type and name should be valid C syntax for a parameter declaration. + +Additional paragraphs and lists can be used in the description to describe more complex +requirements when required for the parameter. + +Placement rules: + +Must be nested within a `.. function::` or `.. macro::` directive. + +Output/effect: + +The parameters to the function or macro are rendered in a list immediately after the API +element signature, in the order declared in the .rst file. + +The first sentence of the description is used as the Doxygen `@param` text in generated +header files, typically used by IDEs for code completion support. + +Example: + +```rst +.. param:: size_t buf_len + Length of buffer ``buf``. +``` + +#### `.. output::` + +Purpose: + +Document an additional output from a function. + +Additional outputs are those written into objects or buffers that are passed by +non-const pointer to the function. + +Syntax: + +```rst +.. output:: + Output description. +``` + +The output-location is typically written as `*p`, where `p` is a buffer or output +parameter that is passed by pointer. + +Placement rules: + +Must be nested within a `.. function::` or `.. macro::` directive. In the source file, +these can be placed alongside the related `.. param::` directive, or grouped elsewhere +in the API element directive. + +Output/effect: + +The output descriptions are rendered in a list following the parameter definitions, in +the order declared in the .rst file. + +Example: + +```rst +.. output:: *buf + On success, the data is written to the buffer pointed to by `buf`. +``` + +Gotchas: + +These are used rarely in the PSA API specifications. At present, they currently only +appear in the Attestation API. + +Most of the API specifications describe the values output in such parameters as part of +the parameter description, instead of using both a `.. param::` and `.. output::` +directive. For example: + +```rst +.. param:: uint8_t * nonce + Buffer where the generated nonce is to be written. +.. param:: size_t * nonce_length + On success, the number of bytes of the generated nonce. +``` + +#### `.. return::` + +Purpose: + +Document the return from a function, or function-like macro. + +Syntax: + +```rst +.. return:: [] + Return description. +``` + +For function-like macros, the type should be omitted. + +For functions that return a status code, such as `psa_status_t`, the description is +usually omitted if the return values are described using `.. retval::` directives. + +For simple functions or macros, the computation or evaluation that is performed can be +documented here. + +Placement rules: + +Must be nested within a `.. function::` or `.. macro::` directive. + +Output/effect: + +The type forms part of the function signature. + +The return value is described after the parameters and outputs. + +The first sentence of the description is used as the Doxygen `@returns` text in +generated header files, typically used by IDEs for code completion support. + +Examples: + +```rst +.. return:: size_t + The number of bytes read from the message parameter. +``` + +Gotchas: + +Technically, this is required for a function that has a `void` return. If none is +provided, a warning is used during the build, and `void` is assumed. + +This directive is not required for `.. macro::` API elements. + +#### `.. retval::` + +Purpose: + +Document a specific return value, or range of return values from a function. + +Syntax: + +```rst +.. retval:: + Return value description. +``` + +The directive argument can be a status code, such as `PSA_ERROR_INVALID_ARGUMENT`, or +can be an expression, such as `> 0`. When rendered, any API elements are hyperlinked to +their definition. + +Placement rules: + +Must be nested within a `.. function::` or `.. macro::` directive. + +Output/effect: + +The return values are described after the return type. Return values are listed in the +same order as the source, except when the `'error_order'` attribute is set in `doc_info` +in `conf.py`. + +Examples: + +```rst +.. retval:: PSA_SUCCESS + The operation completed successfully. +``` + +#### `.. field::` + +Purpose: + +Document a member field in a structure. + +Syntax: + +```rst +.. field:: + Field member description. +``` + +The type and name should be valid C syntax for a structure member declaration. + +Placement rules: + +Must be nested within a `.. struct::` directive. + +Output/effect: + +The members of a structure are rendered in a list immediately after the API structure +signature, in the order declared in the .rst file. + +The first sentence of the description is used as the Doxygen `@brief` text in generated +header files, typically used by IDEs for code completion support. + +Example: + +```rst +.. field:: uint8_t major + Major version number. +``` + +#### `.. value::` + +Purpose: + +Document an enumeration member value. + +Syntax: + +```rst +.. value:: {|} + Value member description. +``` + +The directive argument must be a valid C declaration of an enumeration member. + +Placement rules: + +Must be nested within a `.. enum::` directive. + +Output/effect: + +The members of an enumeration are rendered in a list immediately after the API +enumeration signature, in the order declared in the .rst file. + +The first sentence of the description is used as the Doxygen `@brief` text in generated +header files, typically used by IDEs for code completion support. + +Example: + +```rst +.. value:: block = 0 + Wait for a result. +.. value:: no_block = 1 + Return current status immediately. +``` + +#### `.. subsection::` + +Purpose: + +Provide an additional sub-titled section of the API element documentation. + +This is useful for providing additional information about API elements in a consistent +manner throughout a specification. For example, the 'Key format' sections in the Crypto +API key type definitions and the 'Compatible key types' sections in the Crypto API +algorithm definitions. + +Syntax: + +```rst +.. subsection:: + + Subsection content. +``` + +Common options: + +- `:top:` (optional) - a flag to indicate that this subsection should precede the API + element Description. If not provided, the default placement is after the API element + Description. + +Placement rules: + +Must be nested within an API element directive. + +Output/effect: + +A new subsection of the API definition is output, either immediately before or +immediately after, the Description for the API element. The placement depends on the use +of the `:top:` option, but is otherwise in the same order as in the .rst source. +Subsection headings are similar to the subheadings for Parameters, Outputs, Returns, and +Description. + +Example: + +```rst +.. subsection:: Availability + + This API is optional. Use `PSA_FRAMEWORK_HAS_MM_IOVEC` to determine availability of this function. +``` + +Repository convention: + +- Prefer `Availability` for describing which framework features, service models, or + execution models an API can be used with. +- Keep the `.. summary::` focused on what the API is or does. +- Do not overload version-markup bodies with availability rules or feature + applicability. +- The use of `Availability` is established, but its canonical placement within an API + entry is still deferred. Keep placement consistent within a local edit pass, and + normalize it later once the integrated API text is more complete. + +### Document assembly directives + +The directives in this section are grouped by where editors normally use them. This +means that related producer/consumer directives are not always adjacent. For example, +`.. reference::` entries are normally authored in front-matter inputs, while `.. +reference-table::` is normally used by a template or by an appendix that chooses to +render the collected references elsewhere. + +A document can override or ignore the configured document template source. For example, +a document can avoid `.. title::` and write its title page directly, or avoid `.. +about::` and write the front matter directly. More commonly, a document uses +front-matter section directives such as `.. references::` with `:hide:`, `:replace:`, or +`:extend:` to adjust selected template sections. + +The current `psa-api-*` templates use an unnumbered front-matter chapter called "About +this document", normally listed under `.. front-matter::`, followed by a numbered +chapter 1 introduction in the main document. + +One non-standard arrangement is a bibliography appendix. In that pattern, the document +writes the front matter directly using template construction directives instead of using +`.. about::`, omits the front-matter References section, and renders the references from +an appendix source that contains the `.. reference::` entries followed by `.. +reference-table::`. + +### Directives Used in `index.rst` + +These directives are normally used in the top-level `index.rst` source. + +The `.. front-matter::`, `.. maintoc::`, and `.. appendix::` directives are based on +Sphinx `.. toctree::`, with additional output controls for the document section. They +support these common options: + +- `:numbered:` - override the section numbering depth. +- `:maxdepth:` - override the table-of-contents depth. + +For HTML output, `:numbered:` is only applied by `.. maintoc::` and `.. appendix::`; +front-matter headings are not numbered in HTML. For LaTeX/PDF output, the +table-of-contents depth is controlled by the configured document template, not per +document section. + +PDF page numbering style is also controlled by the configured document template. The +current `psa-api-*` templates use roman page numbers for front matter and Arabic page +numbers for main content and appendices. + +#### `.. title::` + +Purpose: + +Insert the template title page for the document. + +Syntax: + +```rst +.. title:: + + .. abstract:: + + This document defines ... +``` + +Placement rules: + +This should be the first directive in the top-level `index.rst` file. Any content in the +directive body is parsed before the template title page is included, so it can provide +`.. abstract::` and `.. banner::` inputs. For compatibility with older sources, ordinary +parsed content that remains after processing collector directives is treated as the +`abstract` front-matter section when the selected template defines one. + +Output/effect: + +The directive includes `title-page.rst` from the selected template directory. Templates +that use an `abstract` front-section insert the collected abstract at the +template-defined title page location. + +Gotchas: + +The directive itself has no argument. The document title and metadata come from +`doc_info` in `conf.py` and from the selected template. + +#### `.. abstract::` + +Purpose: + +Provide the content for the title page document abstract. + +Syntax: + +```rst +.. title:: + + .. abstract:: + + This document is ... +``` + +Placement rules: + +If used, this must appear in the body of the `.. title::` directive in the document +index.rst file. + +Output/effect: + +Places an abstract on the title page of the document. + +#### `.. banner::` + +Purpose: + +Provide the content for a highlighted box that is placed on the front page of a +document. + +Syntax: + +```rst +.. title:: + + .. banner:: BETA RELEASE + + Status description. +``` + +Placement rules: + +If used, this must appear in the body of the `.. title::` directive in the document +index.rst file. + +Output/effect: + +By default, the banner is only output when the document has a non-zero draft revision, +but this can be overridden by adding `'banner'` to the `doc_info['include_content']` +configuration attribute. + +#### `.. front-matter::` + +Purpose: + +A toc-like directive used in the top-level `index.rst` file to define the front-matter +content of the document. + +Syntax: + +```rst +.. front-matter:: + :maxdepth: 2 + + about/about +``` + +Common options: + +- `:numbered:` - accepted, but ignored for HTML output. The default value is `0`, which + gives unnumbered front-matter headings in PDF output. +- `:maxdepth:` - defaults to `2`. + +Gotchas: + +- Like the `.. toctree::` directive, the contents are treated as a list of content + files, and must not be reflowed as a paragraph if modifying indentation and source + layout. +- This is normally used by Arm-style `psa-api-*` templates for the unnumbered "About + this document" chapter. GP-style documents normally put `about/about` at the start of + `.. maintoc::` instead. + +#### `.. maintoc::` + +Purpose: + +A toc-like directive used in the top-level `index.rst` file to define the main body +content of the document. + +Syntax: + +```rst +.. maintoc:: + :numbered: 3 + :maxdepth: 3 + + intro + architecture +``` + +Common options: + +- `:numbered:` - defaults to `3`. +- `:maxdepth:` - defaults to `3`. + +Gotchas: + +- Like the `.. toctree::` directive, the contents are treated as a list of content + files, and must not be reflowed as a paragraph if modifying indentation and source + layout. +- In GP-style documents, include `about/about` as the first entry so the + template-provided Introduction chapter is numbered as chapter 1. + +#### `.. appendix::` + +Purpose: + +A toc-like directive used in the top-level `index.rst` file to define the appendix +content of the document. + +Syntax: + +```rst +.. appendix:: + :numbered: 3 + :maxdepth: 3 + + appendix/reference-headers +``` + +Common options: + +- `:numbered:` - defaults to `3`. +- `:maxdepth:` - defaults to `3`. + +Gotchas: + +- Like the `.. toctree::` directive, the contents are treated as a list of content + files, and must not be reflowed as a paragraph if modifying indentation and source + layout. +- Appendix chapters use alphabetic numbering in HTML and PDF output. +- The current templates use Arabic appendix page numbers in PDF output, but this is a + template convention rather than a directive behavior. + +### Directives Used in the Front-Matter Chapter + +These directives are normally used in the source that provides template front-section +content, typically `about.rst`, or in files included by that source such as `releases`, +`references`, and `terms`. In Arm-style documents, that source is normally listed by `.. +front-matter::`. In GP-style documents, that source is normally the first entry under +`.. maintoc::`. + +The common pattern is: + +1. Include or define releases, references, and terms. +2. Add front-matter section directives to hide, replace, or extend template sections. +3. End the source with `.. about::`, which includes the configured document template's + `about-chapter.rst` and consumes the previously collected content. + +Placement rule for collected front-matter content: + +The content-providing directives must appear before the directive that renders that +content, in the same source document after includes have been expanded. + +For example: + +- Include or define `.. release::` entries before `.. release-table::`. +- Include or define `.. reference::` entries before `.. reference-table::`. +- Include or define `.. term::`, `.. scterm::`, and `.. abbr::` entries before `.. + term-table::`. +- Place front-matter section directives before `.. about::` or `.. insert-section::`. +- Place `.. banner::` before `.. insert-banner::`. + +The usual pattern is to define `releases`, `references`, and `terms` in extensionless +include files, include those files from `about.rst`, apply any front-matter section +controls such as `.. introduction::`, `.. audience::`, or `.. api-status::`, and then +end `about.rst` with `.. about::`. + +#### `.. release::` + +Purpose: + +Define a release entry for the document releases table. + +Syntax: + +```rst +.. release:: + :date: + + Release summary +``` + +Placement rules: + +See the placement rule for collected front-matter content above. + +The most common pattern is to have all releases defined in a `releases` source file that +is included in the `about.rst` source. The definitions can also just be inline within +the `about.rst` source file. + +Gotchas: + +- Releases in the table appear in the same order as the `.. release::` directives in + the source .rst file. +- Keep the release text summary concise, as this is part of a table of releases. + Detailed change information is better to maintain in a document appendix, with a + reference to the appendix from the `.. release-info::` section. + + To add a reference to a change-history appendix, the following text can be added to `about.rst`: + + ```rst + .. release-info:: + :extend: + + For a detailed list of changes in each document version, see :secref:`change-history`. + ``` + + Provide a named anchor for the section reference in the appendix source immediately before the heading: + + ```rst + .. _change-history: + + Document changes + ================ + ``` + +#### `.. term::`, `.. scterm::`, and `.. abbr::` + +Purpose: + +Define a glossary entry for the document's Terms and abbreviations table. + +The `.. scterm::` directive defines a small-caps-styled term, used for terminology in +the document that has very specific meaning. The `.. abbr::` directive defines an +abbreviation-only entry. + +Syntax: + +```rst +.. term:: + :abbr: + + Definition + +.. abbr:: + + Meaning +``` + +Common options: + +- `:abbr:` (optional) - an abbreviation of the term. This will automatically include an + additional glossary entry for the abbreviation, referring to the full term definition. + +Placement rules: + +See the placement rule for collected front-matter content above. + +The most common pattern is to have all terms defined in a `terms` source file that is +included in the `about.rst` source. The definitions can also just be inline within the +`about.rst` source file. + +Output/effect: + +- Creates one or two definitions in the terms and abbreviations data. +- Creates a link target for the term, and abbreviation if provided, that can be + referenced with the `:term:` and `:scterm:` roles. + +Gotchas: + +The current PSA API templates usually render a single combined terms and abbreviations +table. + +#### `.. reference::` + +Purpose: + +Define a citation reference entry for the document's References table. + +Syntax: + +```rst +.. reference:: + :title: + :author: <author> + :doc_id: <pub_id> + :kind: normative + :publication: <date|location> + :url: <url> +``` + +The directive argument is the citation identifier used within the document text to refer +to this particular external document or website. + +For an RFC document, `RFC nnnn` is the canonical rendered form. Compact source forms +such as `RFCnnnn` are normalized so the `:rfc:` and `:rfc-title:` roles can correctly +link to the citation. + +Common options: + +- `:title:` (required) - The document title or website name. +- `:author:` (optional) - The person or organization that produced the document. +- `:doc_id:` (optional) - The publisher's own identifier number or label. +- `:kind:` (optional) - The reference classification, either `normative` or + `informative`. The default is `normative`. +- `:publication:` (optional) - The date or location of the published document. +- `:url:` (optional) - A URL to the document or the publishing organization. If the URL + text does not start with 'https://' - this is added to the anchor link automatically, + but not rendered in the anchor text. + +Placement rules: + +See the placement rule for collected front-matter content above. + +The most common pattern is to have all references defined in a `references` source file +that is included in the `about.rst` source. The definitions can also just be inline +within the `about.rst` source file. + +Output/effect: + +- Creates a citation reference in the References table. +- Creates a link target for the citation that can be referenced with the `:cite:`, + `:cite-title:`, `:rfc:`, and `:rfc-title:` roles. + +Gotchas: + +References do not have to be rendered in the front matter. To move references to an +appendix, hide or replace the front-matter `.. references::` section, then place the `.. +reference::` directives and `.. reference-table::` in an appendix source. + +The current PSA API templates render a single combined references table. + +#### Front-matter section directives + +Purpose: + +Customize front-matter sections provided by the configured document template. + +Syntax: + +```rst +.. release-info:: + :extend: + + For a detailed list of changes, see :secref:`change-history`. +``` + +Common options: + +- `:replace:` - replace the template's default content for this section. +- `:extend:` - append this content to the template's default content. +- `:hide:` - suppress this section. + +At most one of these options can be provided in a directive. + +- If no option is provided and the directive has content, the content replaces the + default section content. Prefer using the `:replace:` option explicitly. +- If no option and no content are provided, the section is treated as hidden. This is + deprecated usage, it is recommended to explicitly specify `:hide:`. + +Supported section directives are defined by the selected template. The GP template +currently provides: + +- `.. introduction::` +- `.. api-status::` +- `.. feedback::` +- `.. audience::` +- `.. license::` +- `.. references::` +- `.. terms::` +- `.. abbreviations::` +- `.. release-info::` +- `.. todos::` + +The PSA API 2022 and 2025 templates provide the older Arm-style section set: + +- `.. abstract::` +- `.. release-info::` +- `.. todos::` +- `.. license::` in the 2025 template +- `.. references::` +- `.. terms::` +- `.. potential-for-change::` +- `.. conventions::` +- `.. pseudocode::` +- `.. assembler::` +- `.. current-status::` +- `.. feedback::` +- `.. inclusive-language::` + +Placement rules: + +These directives normally appear in a consuming document's `about.rst` before the final +`.. about::` directive. See the placement rule for collected front-matter content above. + +#### `.. about::` + +Purpose: + +Include the about-chapter source from the configured document template. + +Syntax: + +```rst +.. about:: +``` + +Placement rules: + +This is normally used at the end of the consuming document's `about.rst` source after +any releases, references, terms, and front-matter section overrides have been defined. +See the placement rule for collected front-matter content above. + +Output/effect: + +The directive includes `about-chapter.rst` from the configured document template +directory. The template's `about-chapter.rst` provides the default content and structure +for front matter sections, which is modified according to the preceding directives in +the `about.rst` source file. + +### Directives Used to Construct Template Title Pages and Front Matter + +These directives are primarily used in template sources, such as `title-page.rst` and +`about-chapter.rst`. Specification sources can use them directly when they intentionally +bypass part of the configured document template, but that should be a deliberate +document-structure decision. + +The rendering directives in this section must appear after the corresponding +content-providing directives have been defined or included in the same source document. +See the placement rule for collected front-matter content above. + +#### `.. template-image::` + +Purpose: + +Insert an image from the selected template directory. + +Syntax: + +```rst +.. template-image:: logo.svg + :alt: Logo +``` + +Placement rules: + +This directive is primarily for template sources, such as title pages. It accepts the +same image options as the standard reStructuredText `.. image::` directive. + +Output/effect: + +The image path is resolved relative to the selected template directory instead of +relative to the document source file. + +#### `.. insert-banner::` + +Purpose: + +Insert the title-page banner collected from a `.. banner::` directive. + +Syntax: + +```rst +.. insert-banner:: +``` + +Placement rules: + +This is primarily a title-page template directive. Use this after the corresponding `.. +banner::` directive has been defined or included in the same source document. + +Output/effect: + +The collected banner content is inserted only when banner output is enabled. + +#### `.. insert-section::` + +Purpose: + +Insert a front-matter section. The directive defines the section title and the default +content when used in a template. + +When rendered, the content is modified, extended, or removed as directed by a +corresponding front-matter directive in the specification's `about.rst` source. + +Syntax: + +```rst +.. insert-section:: Release information + :section: release-info + :break-after: +``` + +Common options: + +- `:section:` - required; the front-matter section key to insert. +- `:break-after:` - insert a page break after the section in PDF output. +- `:class:` - wrap the section content in the named class or environment. +- `:not-in-toc:` - render a styled title without creating a section in the table of + contents. +- `:keep-if-empty:` - keep the section even if no content is available. + +Placement rules: + +This is primarily a template directive. Specification sources normally use the +front-matter section directives instead to control or modify the template content. Use +this after the corresponding front-matter section directive has been defined or included +in the same source document. + +#### `.. release-table::` + +Purpose: + +Render the release entries collected from `.. release::` directives. + +Syntax: + +```rst +.. release-table:: +``` + +Placement rules: + +Use this after the corresponding `.. release::` entries have been defined or included in +the same source document. + +Output/effect: + +Creates a table with Date, Version, and Change columns. + +#### `.. reference-table::` + +Purpose: + +Render the references collected from `.. reference::` directives. + +Syntax: + +```rst +.. reference-table:: Documents referenced by this document + :sorted: + :kind: all + :layout: by-ref +``` + +Common options: + +- `:sorted:` - sort the references alphabetically by their reference identifier. +- `:kind:` - one of `normative`, `informative`, or `all`. The default is `all`. +- `:layout:` - one of `by-ref` or `by-id`. The default is `by-ref`. +- `:filter:` - one of `with-id`, `without-id`, or `none`. The historical names `arm` and + `non-arm` are accepted as aliases for `with-id` and `without-id`, respectively, so + older specification sources continue to build. +- `:class:` - apply a table class. +- `:name:` - set an explicit target name for the table. + +Placement rules: + +Use this after the corresponding `.. reference::` entries have been defined or included +in the same source document. It can be used in another document source, such as an +appendix, if the document chooses to render references outside the front matter. + +Output/effect: + +Creates a References table. When `:filter: without-id` is used, the document-number +column is omitted in the default `by-ref` layout, preserving the table format for +references that do not have publisher document identifiers. + +The `by-ref` layout produces Ref, Document Number, and Title columns. The `by-id` layout +produces Standard/specification, Description, and Reference columns. In the `by-id` +layout, the Standard/specification column uses `:doc_id:` when it is available and falls +back to the citation identifier when a reference has no publisher document identifier. +The Reference column contains the citation form used in the document text, such as +`[PSA-SM]`. + +#### `.. term-table::` + +Purpose: + +Render the terms and abbreviations collected from `.. term::`, `.. scterm::`, and `.. +abbr::` directives. + +Syntax: + +```rst +.. term-table:: + :sorted: + :kind: all +``` + +Common options: + +- `:sorted:` - sort the terms alphabetically by their normalized identifier. +- `:kind:` - one of `terms`, `abbreviations`, or `all`. The default is `all`. + +Placement rules: + +Use this after the corresponding term or abbreviation entries have been defined or +included in the same source document. + +Output/effect: + +Creates a table from the collected terminology data. With `:kind: terms`, the table has +Term and Definition columns. With `:kind: abbreviations`, the table has Abbreviation and +Meaning columns. Each entry also becomes the target for `:term:` and `:scterm:` +references. + +If no matching entries have been collected, no table is rendered. + +#### `.. include-license::` + +Purpose: + +Include the license text selected by the document configuration. + +Syntax: + +```rst +.. include-license:: +``` + +Placement rules: + +This is primarily a front-matter template directive. It specifies where the configured +license should be included in the document. + +Output/effect: + +The directive first looks for a license source matching the configured license value +relative to the document. If none is found, it looks in the `tools/license/` directory, +using a lower-case filename with hyphens converted to underscores and an `.rst` suffix. +If no matching license exists, the built-in missing-license text is included and a build +error is reported. + +This allows a template to support multiple licenses without template changes. Selecting +a different license for a document issue is a configuration change, while the license +wording remains centralized in the license source file. + +### Directives Used in License Source Files + +#### `.. license::` + +Purpose: + +Mark explicitly provided license text as the document's license section. + +Syntax: + +```rst +.. license:: + + License text. +``` + +Placement rules: + +This directive is intended for license source files, such as the standardized license +files in `tools/license/`. A document template normally uses `.. include-license::` to +include the configured license file at the correct place in the front matter. + +A document or template can use `.. license::` directly to embed license text in its own +sources, but this is not recommended. Keeping license text in a separate file reduces +normal editing churn and helps avoid accidental deviation from the approved license +wording. + +Output/effect: + +This behaves like a section insertion helper. The PSA API templates use a dedicated +style class when inserting this section in the document and forces a page break after +the section. + +### Modified Standard Directives + +#### `.. rationale::` + +Purpose: + +Include rationale text that is useful while drafting or reviewing a specification, but +is not part of the normal published flow. + +Syntax: + +```rst +.. rationale:: Optional title + + Rationale text. +``` + +Output/effect: + +The content is rendered as an admonition only when rationale output is enabled. +Rationale output is enabled when the document has a non-zero draft revision and can also +be enabled by adding `'rationale'` to `doc_info['include_content']`. + +#### `.. comment::` + +Purpose: + +Include review commentary in the source. + +Syntax: + +```rst +.. comment:: + + Reviewer-facing comment. +``` + +Output/effect: + +The content is rendered as a Commentary admonition only when comment output is enabled +by adding `'comment'` to `doc_info['include_content']`. + +Gotchas: + +Use comments sparingly. They are intended for review builds, not as a substitute for +source comments or issue tracking. + +#### `.. code-block::` + +This directive supports the additional language `xref`. + +When `xref` is used as the argument to this directive, the code block is not rendered +using the normal highlighting engine, but instead has every API element from the current +specification hyperlinked in the output. + +The `xref` language option supports the standard `:linenos:` and `:lineno-start:` +options. + +#### `.. literalinclude::` + +This directive supports the additional language `xref`. When `xref` is used as the +language option, the code block is not rendered using the normal highlighting engine, +but instead has every API element from the current specification hyperlinked in the +output. + +The `xref` language option supports the standard `:linenos:` and `:lineno-start:` +options. + +## Role Reference + +Use the same lightweight format for roles: + +- Purpose +- Syntax +- Example +- Gotchas + +### The Default Reference Role + +Sphinx has a default reference role that is used for any text within single-backticks +without a preceding role specifier. + +The `psa-api-tool` Sphinx extension extends the capabilities of the default reference +role as follows: + +* If the reference text is of the form `[ref_id]`, this is resolved as a `:cite:` role. +* If the reference text is any of `SG.id`, `DM.id`, `AM.id`, `T.id`, or `M.id`, it is + resolved using the associated Threat model element role. +* If the reference is a single API element, it is resolved as a `:code:` role. + +### `:sc:` + +Purpose: + +Render the role text in small caps. + +This role is configured by `psa-api-conf.py` as a common reStructuredText role, rather +than registered by `psa-api-tool.py` as a domain-specific role. + +Syntax/example: + +```rst +The result is :sc:`implementation defined`. +``` + +### `:issue:` + +Purpose: + +Apply the `issue` CSS/LaTeX role class to inline text, normally for visible open-issue +placeholders. + +Syntax/example: + +```rst +:issue:`<<Document ID>>` +``` + +Output/effect: + +The current templates render the role text inline, in red. + +Gotchas: + +This role is configured by `psa-api-conf.py` as a common reStructuredText role. It does +not create or link to an external issue tracker entry. + +### `:code:` + +Purpose: + +Format text as inline code, hyperlinking any API element identifiers that are defined in +this specification. + +Syntax/example: + +```rst +Use a call to :code:`psa_wait(PSA_WAIT_ANY, PSA_BLOCK)` to wait for the next partition event. +``` + +Output/effect: + +The rendered output is formatted as code, hyperlinking every API element to its +definition. + +Gotchas: + +- Use the `:code:` role instead of the default reference role for linking to API + elements if the API definition might be in another specification. This results in code + formatting without a hyperlink if no matching definition is available. +- Use the `:code:` role instead of reStructuredText double backticks for monospace text + if the code contains API elements. + +### `:secref:` + +Purpose: + +Include a formatted, inline cross-reference to a titled section or object anywhere in +the specification. + +This role is similar to the standard `:ref:` role: the target's title is used as the +link text. It is commonly used for section references, but it can also reference titled +listings, tables, and figures. See also `:numref:`. + +Example: + +```rst +See :secref:`programming-api` for details. +``` + +For a reference to a document section, this requires that `programming-api` is defined +as a link target associated with the section heading by defining an explicit anchor in +the source immediately before the heading itself, for example: + +```rst +.. _programming-api: + +Programming API +--------------- +``` + +Output/effect: + +The target's title is rendered as a hyperlink in the output. In HTML output, the link +text uses the template's title-reference styling. In LaTeX/PDF output, the link is +followed by an additional `on page nnn` link when the target is on a different page. + +Gotchas: + +- Make sure all anchor targets are unique in a document. They do not have to exactly + match the text in the section heading. +- To reference a figure, listing, or table, these have to have a title, and have the + anchor name set using the `:name:` option. +- The former `:title:` alias has been removed. Use `:secref:` for title-text cross + references. + +### `:numref:` + +Purpose: + +Include a formatted, inline cross-reference to a numbered object in the document, such +as a listing, table, figure, or section heading. See also `:secref:`. + +Syntax/example: + +```rst +:numref:`table-error-codes` summarizes the errors produced by this API. See also :numref:`error-codes`. +``` + +For a reference to a document section, this requires that `error-codes` is defined as a +link target associated with the section heading by defining an explicit anchor in the +source immediately before the heading itself. + +Output/effect: + +The target's number is rendered as a hyperlink in the output. In PDF output, the +hyperlink text includes the target page number. + +Gotchas: + +- Make sure all anchor targets are unique in a document. They do not have to exactly + match the text in the section heading. +- To reference a figure, listing, or table, these have to have an anchor name set using + the `:name:` option. + +### `:term:` + +Purpose: + +Include a formatted cross-reference to a term or abbreviation that is defined in the +document glossary. + +Syntax/example: + +```rst +The RoT Service runs within a :term:`Secure Partition`. +``` + +The capitalization of the term in the role text does not have to match the +capitalization in the glossary. + +Output/effect: + +The rendered output is a formatted hyperlink, the capitalization of the text is taken +from the role text. + +Gotchas: + +- The term or abbreviation must be defined in a `.. term::` directive. +- To pluralize a term, an escaped-space can be used in the .rst source. For example, + `The :term:``RoT Service``\ s` will render as "The RoT Services", with "RoT Service" + hyperlinked to the glossary. + +### `:scterm:` + +Purpose: + +Include a formatted cross-reference to a smallcaps term or abbreviation that is defined +in the document glossary. + +Syntax/example: + +```rst +Providing a zero-length name is a :scterm:`Programmer error`. +``` + +The capitalization of the term in the role text does not have to match the +capitalization in the glossary. + +Output/effect: + +The rendered output is a smallcaps-formatted hyperlink. + +Gotchas: + +- The term or abbreviation must be defined in an `.. scterm::` directive. + +### `:cite-title:` + +Purpose: + +Include a formatted reference to the title of a cited work. + +Syntax/example: + +```rst +The security model is defined in :cite-title:`PSA_SM`. +``` + +The role text is the citation `ref_id`. + +Output/effect: + +The rendered output is a hyperlink containing the title of the cited work followed by +'[ref_id]'. + +Gotchas: + +- The citation must be defined in a `.. reference:: ref_id` directive. + +### `:cite:` + +Purpose: + +Include an untitled citation reference. + +Syntax/example: + +```rst +:cite:`PSA_SM` also defines the security goals. +``` + +The role text is the citation `ref_id`. + +Output/effect: + +The rendered output is a hyperlink containing '[ref_id]'. + +Gotchas: + +- The citation must be defined in a `.. reference:: ref_id` directive. + +### `:rfc-title:` + +Purpose: + +Include a formatted reference to the title of a published RFC. + +Syntax/example: + +```rst +The algorithm is defined in :rfc-title:`9910`. +``` + +The role text is the RFC number, optionally followed by a '#' and section number. + +Output/effect: + +The rendered output is a hyperlink containing the title of the cited RFC followed by +`[RFC nnnn]`. + +If a section number or appendix letter is included in the role text, a second hyperlink +follows which contains the formatted section number and links directly to that section +of the RFC document. + +Gotchas: + +- The citation must be defined in a `.. reference:: RFC nnnn` directive, or a compact + `RFCnnnn` source form that normalizes to the same citation. + +### `:rfc:` + +Purpose: + +Include an untitled RFC reference. + +Syntax/example: + +```rst +:rfc:`9910#B` discusses the security analysis of the algorithm. +``` + +The role text is the RFC number, optionally followed by a '#' and section number. + +Output/effect: + +The rendered output is a hyperlink containing `[RFC nnnn]`. + +If a section number or appendix letter is included in the role text, a second hyperlink +follows which contains the formatted section number and links directly to that section +of the RFC document. + +Gotchas: + +- The citation must be defined in a `.. reference:: RFC nnnn` directive, or a compact + `RFCnnnn` source form that normalizes to the same citation. + +### `:url:` + +Purpose: + +Render an external URL as a hyperlink. + +Syntax/example: + +```rst +See :url:`example.com/specification`. +``` + +Output/effect: + +If the role text does not include `//`, the link target is prefixed with `https://`. The +visible text is the role text as written. + +## Security Risk Assessment Directives and Roles + +The Sphinx extension includes directives and roles that support structured security risk +assessment content. + +### `.. threat::` + +Purpose: + +Define a structured threat entry. + +Syntax: + +```rst +.. threat:: Threat title + :id: T.example + :deployment-models: DM.PROTECTED, DM.EXPOSED + + .. description:: + + Threat description. + + .. adversarial-model:: + + Relevant adversarial model. + + .. security-goal:: + + Security goal affected by this threat. + + .. unmitigated:: DM.PROTECTED + :impact: H + :likelihood: M + + .. unmitigated:: DM.EXPOSED + :impact: VH + :likelihood: M + + .. mitigations:: + + Mitigations. + + .. residual:: DM.PROTECTED + :impact: L + :likelihood: L + + .. residual:: DM.EXPOSED + :impact: M + :likelihood: L +``` + +Common options: + +- `:id:` - explicit threat identifier. +- `:deployment-models:` - optional comma-separated list of deployment models for which + risk values can be provided. This also defines the order in which deployment-model + columns are rendered. + +Placement rules: + +The sub-directives are parsed inside the `.. threat::` directive body. + +Output/effect: + +The directive renders a section for the threat. The section title contains the threat +identifier, when provided, followed by the threat title. + +If no deployment-model distinction is used, the risk values are rendered as a single +evaluation for the threat. If named deployment models are used, the deployment model row +is rendered before the unmitigated risk rows, and the unmitigated and residual risk rows +use a consistent column layout so each evaluation appears under the relevant +deployment-model title. + +### Threat sub-directives + +The following sub-directives collect prose fields for a threat: + +- `.. description::` +- `.. adversarial-model::` +- `.. security-goal::` +- `.. mitigations::` + +The following sub-directives collect risk values: + +- `.. unmitigated::` +- `.. residual::` + +Risk directives support: + +- An optional directive argument - the deployment-model scope for these risk values. +- `:impact:` - required impact value. +- `:likelihood:` - required likelihood value. +- `:risk:` - optional explicit risk value. If omitted, the tool derives the risk from + the impact and likelihood matrix. + +Accepted abbreviated risk values are `VL`, `L`, `M`, `H`, and `VH`. + +If the optional argument is omitted, the risk values apply to the threat as a whole. If +a deployment-model argument is provided, the risk values apply only to that deployment +model. + +When a threat uses multiple deployment models, use `:deployment-models:` on the `.. +threat::` directive to list the expected deployment models and their presentation order, +and provide matching `.. unmitigated:: <DM>` and `.. residual:: <DM>` entries for each +deployment model. + +Example: + +```rst +.. threat:: Eavesdropping + :deployment-models: DM.PROTECTED, DM.EXPOSED + + .. unmitigated:: DM.PROTECTED + :impact: M + :likelihood: L + + .. residual:: DM.PROTECTED + :impact: M + :likelihood: VL + + .. unmitigated:: DM.EXPOSED + :impact: H + :likelihood: M + + .. residual:: DM.EXPOSED + :impact: M + :likelihood: L +``` + +### SRA definition and reference roles + +Definition roles create a definition target and render a canonical identifier: + +- `:deployment-model:` +- `:adversarial-model:` +- `:security-goal:` +- `:threat:` +- `:mitigation:` + +Reference roles link to those definitions: + +- `:dm:` +- `:am:` +- `:sg:` +- `:t:` +- `:m:` + +The long definition roles and the short reference roles use canonical prefixes: `DM.`, +`AM.`, `SG.`, `T.`, and `M.`. If the prefix is omitted in the role text, the tool adds +it. + +Example: + +```rst +:security-goal:`SG.confidentiality` + +The mitigation is described in :m:`isolate-components`. +``` + +---- + +*Copyright 2018-2026 Arm Limited* diff --git a/tools/docs/specification-lifecycle-workflows.md b/tools/docs/specification-lifecycle-workflows.md new file mode 100644 index 00000000..ae03a703 --- /dev/null +++ b/tools/docs/specification-lifecycle-workflows.md @@ -0,0 +1,83 @@ +<!-- +SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +SPDX-License-Identifier: Apache-2.0 +--> + +# Specification Lifecycle Workflows + +This guide records occasional workflows for maintaining a PSA API specification that is +built with `psa-api-tool`. + +These workflows are separate from the basic setup and build instructions in +`using-psa-api-tool.md`, and from the source editing reference in +`psa-api-tool-notes.md`. They are intended for release managers, specification editors, +and agents doing lifecycle maintenance work. + +The sections below are placeholders to be filled in once the publication process and +repository transfer expectations are settled. + +## Before Starting Work on a New Issue or Version + +Use this workflow after a specification issue or version has been published, and before +the first source changes for the next issue or version are introduced. + +Expected topics: + +- Decide whether the next work is a new issue of the current version, a release + candidate, or a new minor/major version. +- Update `doc_info` publication metadata in `conf.py`. +- Update release-history source entries. +- Reset or update draft, quality, issue, and release-candidate metadata. +- Review filename and document identifier expectations. +- Establish the expected API database baseline before semantic changes begin. +- Check whether generated headers, rendered images, or publication artifacts need to be + reset or regenerated. +- Build the clean starting point and record expected warnings. + +TODO: fill in the exact fields and commands once the publication model is confirmed. + +## Preparing a Release Candidate + +Use this workflow when preparing a candidate build for review before final publication. + +Expected topics: + +- Set release-candidate metadata in `conf.py`. +- Confirm draft and optional-content settings for the candidate review build. +- Update release notes, current status, potential-for-change, and change-history + content. +- Run HTML, PDF, API database, generated-header, and image validation as appropriate. +- Review generated filenames and visible title-page/footer metadata. +- Confirm that intentional API changes are reflected in the checked-in API database. +- Record known and accepted warnings. +- Package or tag review artifacts according to the consuming specification repository + process. + +TODO: define exact validation commands and artifact expectations for PSA API +specifications. + +## Finalizing an Issue or Version for Publication + +Use this workflow when converting an approved release candidate into the final published +issue or version. + +Expected topics: + +- Remove release-candidate metadata and set final quality/status metadata. +- Confirm draft, watermark, license, copyright, owner, and feedback metadata. +- Finalize release-history, current-status, and potential-for-change sections. +- Verify there are no unresolved rendered TODO, rationale, or comment sections unless + intentionally published. +- Run final HTML and PDF builds. +- Run final API database comparison and update generated references when required. +- Regenerate rendered image assets when graphics sources changed. +- Review generated filenames, document identifiers, version strings, and title-page + metadata. +- Create publication artifacts and tags according to the consuming specification + repository process. + +TODO: fill in the exact publication checklist after the release process is agreed. + +---- + +*Copyright 2018-2026 Arm Limited* diff --git a/tools/docs/using-psa-api-tool.md b/tools/docs/using-psa-api-tool.md new file mode 100644 index 00000000..5065f226 --- /dev/null +++ b/tools/docs/using-psa-api-tool.md @@ -0,0 +1,243 @@ +<!-- +SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +SPDX-License-Identifier: Apache-2.0 +--> + +# Building PSA API Specifications + +This guide explains how the PSA API specifications in this repository are built with the +integrated `psa-api-tool` copy in `tools/`. + +For source editing conventions, custom directives, roles, and API documentation +conventions, see `psa-api-tool-notes.md`. + +For occasional lifecycle tasks, such as starting work on a new issue or version, +preparing a release candidate, or finalizing a publication, see +`specification-lifecycle-workflows.md`. That guide intentionally contains placeholders +until the publication process is settled after the repository transfer. + +## Tool Layout + +The repository has a small top-level `Makefile`: + +```make +PSA_API_TOOL ?= tools + +ifeq ($(wildcard $(PSA_API_TOOL)/make),) + $(error The 'PSA_API_TOOL' variable is not set, or does not point to a suitable installation of psa-api-tool) +endif + +include $(PSA_API_TOOL)/make +``` + +By default, builds use the checked-in tool under `tools/`. Editors can override +`PSA_API_TOOL` to test another compatible copy: + +```sh +make PSA_API_TOOL=/path/to/psa-api-tool doc/crypto/html +``` + +Each specification has its own `conf.py` under `doc/<spec>/`. The document configuration +sets `psa_api_tool_path` to the repository `tools/` directory, allows the `PSA_API_TOOL` +environment variable to override that path, then executes `psa-api-conf.py` from the +selected tool copy. + +Each specification directory also contains a minimal `pyproject.toml` file. These files +act as project-boundary markers for editor integrations such as Esbonio, allowing each +specification to have a separate Sphinx session and live preview while using the same +checked-in tool copy. They are not used by the repository make targets. + +Older PSA API source revisions used the former `atg-sphinx-spec` name. The shared +makefile exports `ATG_SPHINX_SPEC` as an alias for `PSA_API_TOOL`, and the tool provides +`atg-sphinx-conf.py` as a compatibility wrapper around `psa-api-conf.py`. This allows +older source trees to be built with the newer tool by invoking: + +```sh +make -f /path/to/psa-api-tool/make doc/crypto/html +``` + +## Requirements + +The core HTML and structured-output build path requires: + +- Python 3. +- Sphinx. +- A POSIX-like shell and `make`. + +PDF output also requires a LaTeX toolchain that provides `pdflatex`. + +The `images` target may require additional tools, depending on the figure sources used +by the specification: + +- `wavedrompy` for `.json` bitfield diagrams. +- Java and PlantUML for `.puml` diagrams. +- `rsvg-convert` for SVG-to-PDF conversion. + +Graphviz is only required for documents that use Sphinx Graphviz directives. + +Most rendered graphics are checked in, so a text-only edit normally does not require the +full graphics toolchain. + +The PDF target uses `qpdf` to optimize generated PDF files when it is available. This is +optional. + +### Version and Platform Guidance + +The build tooling is not currently defined by a pinned requirements file or a repeatable +CI environment. Contributors should report the tool and platform versions used when +diagnosing build differences. + +The integrated tool introduction branch has been tested on macOS arm64 with Python +3.13.7, Sphinx 8.1.0, GNU Make 3.81, MiKTeX-pdfTeX 4.10, OpenJDK 21.0.2, PlantUML +1.2025.2, Graphviz 12.2.1, `rsvg-convert` 2.60.0, and `qpdf` 12.3.2. The precursor +tooling was also used successfully with Git Bash on Windows 11, and the tooling is +expected to work on Linux with the equivalent packages installed. These platforms are +descriptive, not a formal support matrix. + +The tools are maintained against recent Sphinx releases. Sphinx 8.1.0 is the current +known-good version; Sphinx 5.3 is the oldest version expected to be plausible, but it is +not currently validated. When setting up a new environment, start with the newest stable +versions available from the platform package manager, then validate with the specific +targets needed for the change under review. + +## Common Builds + +From the repository root, build one output format for one specification: + +```sh +make doc/crypto/html +make doc/crypto/pdf +make doc/crypto/headers +make doc/crypto/api-diff +``` + +The same pattern works for the other specification directories: + +- `doc/attestation` +- `doc/crypto` +- `doc/crypto-driver` +- `doc/fwu` +- `doc/status-code` +- `doc/storage` + +Build one output format for every specification: + +```sh +make html +make pdf +``` + +Build all default outputs for one specification: + +```sh +make doc/crypto +``` + +Generated output is written under `build/`, mirroring the document path. For example, +`make doc/crypto/html` writes HTML under `build/doc/crypto/html`. + +## Targets + +| Target | Purpose | +| --- | --- | +| `html` | Build HTML output and rewrite it for the repository website layout. | +| `latex` | Generate LaTeX output. | +| `pdf` | Generate LaTeX output, run `pdflatex`, and optimize the PDF with `qpdf` when available. | +| `xml` | Build XML structured document output. | +| `headers` | Generate reference C header files from API directives. | +| `api-db` | Generate normalized API database headers. | +| `api-diff` | Compare generated API database headers with the checked-in `api.db/` reference. | +| `api-update` | Update the checked-in `api.db/` reference after an intentional API change. | +| `images` | Regenerate converted or generated image assets when required tools are installed. | +| `clean` | Remove generated build output for the selected document or documents. | + +Use `INTERNAL=1` to build an internal-tagged output variant when a document uses +internal-only content. + +## Recommended Validation + +For a source-only documentation change, build the affected HTML output first: + +```sh +make doc/<spec>/html +``` + +For a change that affects API directives, generated C declarations, manifest +definitions, or reference API headers, run: + +```sh +make doc/<spec>/api-diff +``` + +If the API change is intentional, review the diff and update the checked-in API +database: + +```sh +make doc/<spec>/api-update +``` + +When publishing a new revision, the reference headers are updated using the output +from the build: + +```sh +make doc/<spec>/headers +``` + +For changes that affect title pages, front matter, page breaks, LaTeX styling, or +publication-ready layout, build: + +```sh +make doc/<spec>/pdf +``` + +For changes to graphics sources, run: + +```sh +make doc/<spec>/images +``` + +The XML output can be useful when reviewing generated document structure, resolved +references, table structure, glossary entries, and API sections: + +```sh +make doc/<spec>/xml +``` + +Treat XML as supplementary validation. It does not replace rendered HTML/PDF inspection +or API database checks. It can be helpful when diagnosing why some source content is +not rendering as expected. + +## Document Configuration + +Each document `conf.py` defines a `doc_info` dictionary and then executes the shared +tool configuration. Keep document configuration focused on document metadata and +document-specific choices. Avoid setting Sphinx configuration variables directly in +`conf.py` unless the shared configuration cannot support the required behavior. + +The current PSA API documents use the Arm-style `psa-api-2022` and `psa-api-2025` +templates. These templates preserve the existing front matter and release metadata model +while allowing the repository to build without an external `atg-sphinx-spec` checkout. + +Important `doc_info` keys used by these specifications include: + +| Key | Purpose | +| --- | --- | +| `template` | Template directory under `tools/templates/`. | +| `title` | Document title used by Sphinx and the title page. | +| `version` | Base API version, normally `X.Y`. | +| `issue_no` | Document issue or maintenance revision. | +| `draft` | Draft flag or draft revision, depending on the selected publication model. | +| `release_candidate` | Release-candidate number for existing Arm-style documents. | +| `quality` | API maturity code such as `ALP`, `BET`, or `REL`. | +| `header` | Default generated C header path for API directives. | +| `header_doxygen` | Generated header annotation level. | +| `error_order` | Document-wide order for generated return values. | +| `identifier_index` | Controls the generated C identifier index. | +| `prolog_files` | Shared substitution files included in the Sphinx prolog. | + +For detailed directive and role behavior, use `psa-api-tool-notes.md` as the editing +reference. + +---- + +*Copyright 2018-2026 Arm Limited* diff --git a/tools/images.mk b/tools/images.mk new file mode 100644 index 00000000..ff569606 --- /dev/null +++ b/tools/images.mk @@ -0,0 +1,89 @@ +# SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +# SPDX-License-Identifier: Apache-2.0 + +# Makefile for building image files (SVG and PDF) from sources + +# The parameter $(IMAGE) must have the location of the image files +IMAGE = . + +# This makefile +MAKEFILE = $(lastword $(MAKEFILE_LIST)) +# The location of this makefile, relative to the current directory +MAKEFILEDIR := $(patsubst %/,%,$(dir $(MAKEFILE))) +# The location of the psa-api-tool tools, containing the PlantUML configuration +SPEC = $(MAKEFILEDIR) + +# Bitfield image generation, command to run to wavedrompy +WAVEDROM = wavedrompy + +# UML image generation, command to run plantuml +JAVA = java +PLANTUML_IPATH = $(SPEC)/puml +PLANTUML = $(JAVA) -Dplantuml.include.path="$(PLANTUML_IPATH)" -jar ~/jar/plantuml.jar +PLANTUML_FLAGS = -nometadata -tsvg -charset utf-8 + +# SVG to PDF conversion +SVG2PDF = rsvg-convert +SVG2PDF_FLAGS = --format=pdf + +OSTYPE = $(shell echo $${OSTYPE}) +ifneq (,$(filter darwin%,$(OSTYPE))) + SED_FLAG = -i '' +else ifneq (,$(filter bsd%,$(OSTYPE))) + SED_FLAG = -i '' +else + SED_FLAG = -i'' +endif + +FIX_SVG_FONTS = sed $(SED_FLAG) -e 's/"roboto mono"/"Roboto Mono,monospace"/gi;s/"roboto"/"Roboto,sans-serif"/gi;s/lato/Lato,sans-serif/gi;s/inconsolata/Inconsolata,monospace/gi' + +# Images can be in sub-directories of those listed in $IMAGE +IMAGES := $(shell find $(IMAGE) -type d -print) + +# List of UML diagrams to render +UML_IMAGES := $(wildcard $(addsuffix /*.puml,$(IMAGES))) +# List of bitfield descriptions to render +BIT_IMAGES := $(wildcard $(addsuffix /*.json,$(IMAGES))) +# Build a list of source SVG image files to convert +SVG_IMAGES := $(sort $(patsubst %.json,%.svg,$(BIT_IMAGES)) \ + $(patsubst %.puml,%.svg,$(UML_IMAGES)) \ + $(wildcard $(addsuffix /*.svg,$(IMAGES))) \ + ) +# Build a list of generated PDF files +PDF_IMAGES := $(patsubst %.svg,%.pdf,$(SVG_IMAGES)) + +PUML_INCLUDES := $(wildcard $(PLANTUML_IPATH)/*) + +# Pattern rule for identifying UML files to rebuild +%.svg : %.puml $(MAKEFILE) $(PUML_INCLUDES) + @echo "Rendering $<"; \ + $(PLANTUML) $(PLANTUML_FLAGS) $< ; \ + $(FIX_SVG_FONTS) $@ + +# Pattern rule for converting JSON to SVG +%.svg : %.json $(MAKEFILE) + @echo "Rendering $<"; \ + $(WAVEDROM) -i $< -s $@; \ + $(FIX_SVG_FONTS) $@ + +# Pattern rule for identifying SVG files to convert +%.pdf : %.svg + @echo "Converting $<"; \ + $(SVG2PDF) $(SVG2PDF_FLAGS) -o $@ $< + +.PHONY: all +all: svg pdf + +.PHONY: svg +svg: $(SVG_IMAGES) + +.PHONY: pdf +pdf: $(PDF_IMAGES) + +.PHONY: help +help: + @echo "To build the graphics, please use \`make <target>' where <target> is one of"; \ + echo " svg to make the SVG image files"; \ + echo " pdf to make the PDF image files"; \ + echo ""; \ + echo " all to make all image files" diff --git a/tools/license/arm_psa_certified_api_license.rst b/tools/license/arm_psa_certified_api_license.rst new file mode 100644 index 00000000..2216685b --- /dev/null +++ b/tools/license/arm_psa_certified_api_license.rst @@ -0,0 +1,40 @@ +.. SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license AND Apache-2.0 + +.. + The license for the text and illustrations is CC BY-SA 4.0 with and additional patent clause derived from Apache License 2.0. + The license for source code within the document is Apache License 2.0. + + CC BY-SA 4.0 is at https://creativecommons.org/licenses/by/4.0 + Apache 2.0 is at https://www.apache.org/licenses/LICENSE-2.0 + +.. license:: + + .. insert-section:: Text and illustrations + :not-in-toc: + + Text and illustrations in this work are licensed under Attribution-ShareAlike 4.0 International (CC BY-SA 4.0). To view a copy of the license, visit :url:`creativecommons.org/licenses/by-sa/4.0`. + + **Grant of patent license**. Subject to the terms and conditions of this license (both the CC BY-SA 4.0 Public License and this Patent License), each Licensor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Licensed Material, where such license applies only to those patent claims licensable by such Licensor that are necessarily infringed by their contribution(s) alone or by combination of their contribution(s) with the Licensed Material to which such contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Licensed Material or a contribution incorporated within the Licensed Material constitutes direct or contributory patent infringement, then any licenses granted to You under this license for that Licensed Material shall terminate as of the date such litigation is filed. + + The Arm trademarks featured here are registered trademarks or trademarks of Arm Limited (or its subsidiaries) in the US and/or elsewhere. All rights reserved. Please visit :url:`arm.com/company/policies/trademarks` for more information about Arm's trademarks. + + .. insert-section:: About the license + :not-in-toc: + + The language in the additional patent license is largely identical to that in section 3 of the Apache License, Version 2.0 (Apache 2.0), with two exceptions: + + 1. Changes are made related to the defined terms, to align those defined terms with the terminology in CC BY-SA 4.0 rather than Apache 2.0 (for example, changing "Work" to "Licensed Material"). + + 2. The scope of the defensive termination clause is changed from "any patent licenses granted to You" to "any licenses granted to You". This change is intended to help maintain a healthy ecosystem by providing additional protection to the community against patent litigation claims. + + To view the full text of the Apache 2.0 license, visit :url:`apache.org/licenses/LICENSE-2.0`. + + .. insert-section:: Source code + :not-in-toc: + + Source code samples in this work are licensed under the Apache License, Version 2.0 (the "License"); you may not use such samples except in compliance with the License. You may obtain a copy of the License at :url:`apache.org/licenses/LICENSE-2.0`. + + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + + See the License for the specific language governing permissions and limitations under the License. diff --git a/tools/license/missing.rst b/tools/license/missing.rst new file mode 100644 index 00000000..66689649 --- /dev/null +++ b/tools/license/missing.rst @@ -0,0 +1,8 @@ +.. SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +.. The license is missing from the document information + +.. license:: <<Missing license>> + + :issue:`<<Missing license text>>` diff --git a/tools/license/psa_certified_api_license.rst b/tools/license/psa_certified_api_license.rst new file mode 100644 index 00000000..863d7c57 --- /dev/null +++ b/tools/license/psa_certified_api_license.rst @@ -0,0 +1,38 @@ +.. SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license AND Apache-2.0 + +.. + The license for the text and illustrations is CC BY-SA 4.0 with and additional patent clause derived from Apache License 2.0. + The license for source code within the document is Apache License 2.0. + + CC BY-SA 4.0 is at https://creativecommons.org/licenses/by/4.0 + Apache 2.0 is at https://www.apache.org/licenses/LICENSE-2.0 + +.. license:: + + .. insert-section:: Text and illustrations + :not-in-toc: + + Text and illustrations in this work are licensed under Attribution-ShareAlike 4.0 International (CC BY-SA 4.0). To view a copy of the license, visit :url:`creativecommons.org/licenses/by-sa/4.0`. + + **Grant of patent license**. Subject to the terms and conditions of this license (both the CC BY-SA 4.0 Public License and this Patent License), each Licensor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Licensed Material, where such license applies only to those patent claims licensable by such Licensor that are necessarily infringed by their contribution(s) alone or by combination of their contribution(s) with the Licensed Material to which such contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Licensed Material or a contribution incorporated within the Licensed Material constitutes direct or contributory patent infringement, then any licenses granted to You under this license for that Licensed Material shall terminate as of the date such litigation is filed. + + .. insert-section:: About the license + :not-in-toc: + + The language in the additional patent license is largely identical to that in section 3 of the Apache License, Version 2.0 (Apache 2.0), with two exceptions: + + 1. Changes are made related to the defined terms, to align those defined terms with the terminology in CC BY-SA 4.0 rather than Apache 2.0 (for example, changing "Work" to "Licensed Material"). + + 2. The scope of the defensive termination clause is changed from "any patent licenses granted to You" to "any licenses granted to You". This change is intended to help maintain a healthy ecosystem by providing additional protection to the community against patent litigation claims. + + To view the full text of the Apache 2.0 license, visit :url:`apache.org/licenses/LICENSE-2.0`. + + .. insert-section:: Source code + :not-in-toc: + + Source code samples in this work are licensed under the Apache License, Version 2.0 (the "License"); you may not use such samples except in compliance with the License. You may obtain a copy of the License at :url:`apache.org/licenses/LICENSE-2.0`. + + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + + See the License for the specific language governing permissions and limitations under the License. diff --git a/tools/make b/tools/make new file mode 100644 index 00000000..5fdc3644 --- /dev/null +++ b/tools/make @@ -0,0 +1,267 @@ +# SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +# SPDX-License-Identifier: Apache-2.0 + +# Common top level include-makefile for building a suite of documents +# +# This should be included from the specification project makefile, +# with the following variables defined: + +# OUTPUT optional - it specifies the output directory, default to 'build' +OUTPUT ?= build +# INTERNAL optional - boolean, if non-empty this sets the 'internal' tag on the documentation build + +# Use the directory containing this makefile for the psa-api-tool tools +override PSA_API_TOOL := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))) +export PSA_API_TOOL +# Compatibility for older specification sources that still load +# atg-sphinx-conf.py using ATG_SPHINX_SPEC. +override ATG_SPHINX_SPEC := $(PSA_API_TOOL) +export ATG_SPHINX_SPEC +# For recursive invokation we need to know which makefile is used +THIS_MAKE := -f $(firstword $(MAKEFILE_LIST)) + +ifeq ($(wildcard conf.py),) + +############################### +# Document project make rules # +############################### + +# There is no conf.py - this is a project directory + +# The set of valid format targets for individual documents +TARGETS := clean html latex pdf xml headers api-db api-diff api-update images +TARGETS_ALL := $(TARGETS) all + +# The set of document Sphinx configuration files +DOCS := $(patsubst ./%/conf.py,%,$(shell find . -name conf.py)) +# compile the set of directories containing documents, and their parents +DOCS2 := $(patsubst %/,%,$(subst ./,,$(dir $(DOCS)))) +DOCS3 := $(patsubst %/,%,$(subst ./,,$(dir $(DOCS2)))) +DOCS4 := $(patsubst %/,%,$(subst ./,,$(dir $(DOCS3)))) +DOCS_ALL := $(sort $(DOCS) $(DOCS2) $(DOCS3) $(DOCS4)) + +# The full combination of all documents and targets +ALL_TARGETS := $(foreach DOC,$(DOCS_ALL),$(addprefix $(DOC)/,$(TARGETS_ALL))) + +MAKE_VARS := INTERNAL=$(INTERNAL) + +.PHONY: all +all: $(addsuffix /all,$(DOCS)) + +# Building all target types for a specific document +.PHONY: $(DOCS_ALL) +$(DOCS_ALL): + @"$(MAKE)" $(THIS_MAKE) $@/all \ + OUTPUT=$(OUTPUT) $(MAKE_VARS) + +# Building a specific target type for each document +.PHONY: $(TARGETS) +$(TARGETS): + @"$(MAKE)" $(THIS_MAKE) $(addsuffix /$@,$(DOCS)) \ + OUTPUT=$(OUTPUT) $(MAKE_VARS) + +# Explicitly using all/* to build a certain target type +.PHONY: all/% +all/%: %; + +# Building a single target type for a single document + +.PHONY: $(ALL_TARGETS) +$(ALL_TARGETS): + @if [ -e $(@D)/Makefile ]; then \ + MAKEFILE="Makefile" ; \ + else \ + MAKEFILE="$(PSA_API_TOOL)/make" ; \ + fi; \ + "$(MAKE)" -C $(@D) $(@F) -f $$MAKEFILE \ + OUTPUT=$(abspath $(OUTPUT))/$(@D) $(MAKE_VARS) + +else + +############################## +# Single document make rules # +############################## + +# There is a conf.py - this is a document directory + +# SOURCE optional - specifies the source directory, default . +SOURCE ?= . + +# FIGURES optional - a set of directories containing images to generate/transform. Default 'figure' +FIGURES ?= figure + +# Support for maintaining API compatibility (optional) +# Can be overriden by a value in the makefile that includes this +API_PATH ?= api.db + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal builds output to the .../internal path and set the "internal" tag +ifneq ($(strip $(INTERNAL)),) +override OUTPUT := $(OUTPUT)/internal +SPHINXOPTS += -t internal +endif + +# Internal variables. +ALLSPHINXOPTS := -d $(OUTPUT)/doctrees $(SPHINXOPTS) -T $(SOURCE) + +.PHONY: all +all: html latex pdf xml headers + +ifneq ($(wildcard $(FIGURES)),) +# Rebuild converted and generated images if graphic sources are modified +.PHONY: images +images: + @"$(MAKE)" -f $(PSA_API_TOOL)/images.mk IMAGE=$(FIGURES) +else +.PHONY: images +images: + @echo "No images in this document" +endif + +# Assume all content under SOURCE and PSA_API_TOOL tooling affects the output +PRUNE := .* __* skeleton guide build docs +PRUNE := $(patsubst %,-name "%" -prune -or,$(PRUNE)) +PSA_API_TOOL_FILES := $(shell find $(PSA_API_TOOL) $(PRUNE) -type f -print) +SPHINX_INPUTS := $(shell find $(SOURCE) -type f -print) $(PSA_API_TOOL_FILES) + +.PHONY: html +html: $(OUTPUT)/html/done +$(OUTPUT)/html/done: $(SPHINX_INPUTS) + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(@D) + @pushd $(@D); python3 $(PSA_API_TOOL)/rewrite-html-for-jekyll.py; popd; \ + touch $@; echo; echo "Build finished. The HTML pages are in $(@D)." + +.PHONY: latex +latex: $(OUTPUT)/latex/done +$(OUTPUT)/latex/done: $(OUTPUT)/latex/donetex + @touch $@; echo; echo "Build finished; the LaTeX files are in $(OUTPUT)/latex."; \ + echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make pdf' here to do that automatically)." +$(OUTPUT)/latex/donetex: $(SPHINX_INPUTS) + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(@D) + @touch $@ + +.PHONY: pdf +pdf: $(OUTPUT)/latex/donepdf +$(OUTPUT)/latex/donepdf : $(OUTPUT)/latex/donetex + @echo "Running LaTeX files through pdflatex..."; \ + "$(MAKE)" -C $(OUTPUT)/latex all-pdf; \ + if command -v qpdf >/dev/null 2>&1; then \ + for pdf in "$(@D)"/*.pdf; do \ + [ -e "$$pdf" ] || continue; \ + qpdf --linearize --object-streams=generate --compress-streams=y --replace-input "$$pdf"; \ + done; \ + fi; \ + touch $@; echo ; echo "Build finished; the PDF files are in $(@D)." + +.PHONY: xml +xml: $(OUTPUT)/xml/done +$(OUTPUT)/xml/done: $(SPHINX_INPUTS) + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(@D) + @touch $@; echo; echo "Build finished. The XML files are in $(@D)." + +API_REF_BUILD_PATH = $(OUTPUT)/headers +API_DB_BUILD_PATH = $(OUTPUT)/api.db +API_DIFF = $(OUTPUT)/api.diff + +.PHONY: headers +headers: $(API_REF_BUILD_PATH) +$(API_REF_BUILD_PATH): $(SPHINX_INPUTS) + @rm -rf $@ + $(SPHINXBUILD) -b headers $(ALLSPHINXOPTS) $@ +# Deal with graphviz extension stupidity of copying .css into every target + @rm -rf $@/_static; \ + echo ; echo "Build finished. The reference header files are in $@." + +.PHONY: api-db +api-db: $(API_DB_BUILD_PATH) +$(API_DB_BUILD_PATH): $(SPHINX_INPUTS) + @rm -rf $@ + $(SPHINXBUILD) -b api-db $(ALLSPHINXOPTS) $@ +# Deal with graphviz extension stupidity of copying .css into every target + @rm -rf $@/_static; \ + echo ; echo "Build finished. The reference header files are in $@." + +.PHONY: api-diff +api-diff: $(API_DIFF) + @if [ -s $(API_DIFF) ]; then \ + echo ; \ + echo "WARNING: API changes detected."; \ + echo ""; \ + cat $(API_DIFF); \ + exit 1; \ + else \ + echo "No API changes detected."; \ + fi + +ifeq (,$(wildcard $(API_PATH))) +# Handle the bootstrap case when there is no reference API +# If there is no API, create an empty diff +$(API_DIFF): $(API_DB_BUILD_PATH) + @if [[ 0 -eq `find $(API_DB_BUILD_PATH) -type f | wc -l` ]]; \ + then \ + >$@; \ + else \ + echo "** No reference API **" > $@; \ + fi +else +$(API_DIFF): $(API_DB_BUILD_PATH) $(API_PATH) + @diff --strip-trailing-cr -x .DS_Store -r $(API_PATH) $(API_DB_BUILD_PATH) 1>$@ || exit 0 +endif + +.PHONY: api-update +api-update: $(API_DIFF) + @if [ -s $(API_DIFF) ]; then \ + echo "Copying header files"; \ + mkdir -p $(API_PATH) && cp -r $(API_DB_BUILD_PATH)/* $(API_PATH)/; \ + >$(API_DIFF); \ + fi + +.PHONY: clean +clean:: + rm -rf $(OUTPUT)/* + +endif + +.PHONY: help +help:: +ifeq ($(wildcard conf.py),) + @echo "Please use \`make <document>/<target>' where <document> is one of"; \ + echo " $(DOCS)"; \ + echo "and <target> is one of:" +else + @echo "Please use \`make <target>' where <target> is one of" +endif + @echo " html to make standalone HTML files"; \ + echo " xml to make an XML document structure"; \ + echo " latex to make LaTeX files"; \ + echo " pdf to make LaTeX files and run them through pdflatex"; \ + echo " headers to make the API reference header files"; \ + echo ""; \ + echo " all to make all of the above targets"; \ + echo " clean to remove build output for all targets"; \ + echo ""; \ + echo " api-db to generate the API definition"; \ + echo " api-diff to compare the API definition against a reference"; \ + echo " api-update to update the reference API definition"; \ + echo "" +ifneq ($(wildcard conf.py)$(wildcard $(FIGURES)),conf.py) + @echo " images to update generated and converted image files"; \ + echo "" +endif +ifeq ($(wildcard conf.py),) + @echo "Shortcuts:"; \ + echo " \`make <target>' builds <target> for all documents"; \ + echo " \`make <document>' builds all targets for <document>"; \ + echo "" +endif + @echo "Specifying \`INTERNAL=1' to make will build an internal version"; \ + echo "of the documents" diff --git a/tools/psa-api-conf.py b/tools/psa-api-conf.py new file mode 100644 index 00000000..35dc1e83 --- /dev/null +++ b/tools/psa-api-conf.py @@ -0,0 +1,618 @@ +# SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +# SPDX-License-Identifier: Apache-2.0 + +# -*- coding: utf-8 -*- +# +# This is a common set of configuration options for using Sphinx to build +# PSA Certified API specifications. Project specific definitions are contained in +# the conf.py file that forms the master document directory. +# +# This script is included and executed as part of conf.py, it is not a +# standalone python module or script. +# +# conf.py must have set up: +# * a dictionary doc_info, with project specific information and +# configuration. +# * a string path psa_api_tool_path that defines the the path containing this +# file, either relative to conf.py, or absolute. +# + +import sys, os, re +from datetime import date +import importlib + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath(psa_api_tool_path)) + +# When used within the extension, psa_api_tool_path must be a relative path +psa_api_tool_path = os.path.relpath(psa_api_tool_path) + +# Validate the selected document template, or use the default one +def template_path(template): + return os.path.join(psa_api_tool_path, 'templates', template) + +default_template = 'psa-api-2026' + +template = doc_info.get('template', default_template) +psa_api_template_path = template_path(template) +if not os.path.isdir(psa_api_template_path): + print ('WARNING: Document template "{}" not found, falling back to "{}"'.format(template, default_template)) + psa_api_template_path = template_path(default_template) + +# Process any template-specific configuration +# This must provide some required config, such as font info for html/latex +# This can also override, or fill in the doc_info dictionary + +template_info = {} + +template_conf_file = os.path.join(psa_api_template_path,'template-conf.py') +if os.path.exists(template_conf_file): + exec(compile(open(template_conf_file, encoding='utf-8').read(), 'template-conf.py', 'exec')) + +# -- helper functions + +def subst_rst(item): + if type(item) is str: + return re.sub(r'(<<.+>>)',r'\ :issue:`\1`\ ',item) + else: + return item + +def subst_latex(item): + if type(item) is str: + item = item.replace('_',r'\_') + item = re.sub(r'(<<.+>>)',r'\\DUrole{issue}{\1}',item) + return re.sub(r':(.+):`(.+)`',r'\\DUrole{\1}{\2}',item) + else: + return item + +quality_map = { + 'DEV': 'Development', + 'ALP': 'Alpha', + 'BET': 'Beta', + 'REL': 'Final', + } + +def check_quality(quality): + if not quality: + return 'REL' # Default to Final + if quality.upper() in quality_map: + return quality.upper() + for q in quality_map.items(): + if q[1] == quality: + return q[0] + print("error: Invalid doc_info.quality value") + return '<<Quality>>' + +def full_quality(quality): + return quality_map.get(quality, '<<Quality>>') + +status_map = { + 'DFT': 'Draft', + 'CRV': 'Committee Review', + 'CPR': 'Post Committee Review', + 'MRV': 'Member Review', + 'MPR': 'Post Member Review', + 'MRC': 'Member Release Candidate', + 'MEM': 'Member Release', + 'PRV': 'Public Review', + 'PPR': 'Post Public Review', + 'PRC': 'Public Release Candidate', + 'PUB': 'Public Release', + } + +def check_status(status): + if not status: + return None + if status.upper() in status_map: + return status.upper() + for s in status_map.items(): + if s[1] == status: + return s[0] + print("error: Invalid doc_info.status value") + return '<<Status>>' + +def full_status(status): + return status_map.get(status, '<<Status>>') + +def make_release(v, q, i, draft): + release = f'{v}' + release_full = release + if q != 'REL': + release += f'-{q.lower()}' + release_full += f' {full_quality(q)}' + issue = '' + if i > 0 or draft: + issue = f'{i}' + if draft: + issue += f'.{draft}' + if issue: + release += f'.{issue}' + if q == 'REL': + release_full += f'.{issue}' + else: + release_full += f' revision {issue}' + return (release, release_full, issue) + +def split_version(version): + s = [int(x) for x in version.split('.')] + if len(s) == 1: + s.append(0) + return s[0], s[1] + +# -- Build PSA API specification configuration ----------------------------------- + +now = date.today() + +# Extract and build the Sphinx configuration variables and document data +title = doc_info['title'].split('\n') +fulltitle = ' '.join(title) +rsttitle = ' |br| '.join(title) +htmltitle = '<br />'.join(title) +latextitle = '\\par '.join(title) +title = title[-1] + +project = doc_info.get('project', fulltitle) +author = doc_info.get('author', 'Unattributed') +version = doc_info['version'] +owner = doc_info.get('owner') +copyright_date = doc_info.get('copyright_date', now.strftime('%Y')) +doc_id = doc_info.get('doc_id', '<<Document ID>>') +quality = check_quality(doc_info.get('quality')) +quality_full = full_quality(quality) +issue_no = doc_info.get('issue_no', '<<Issue Number>>') +status = check_status(doc_info.get('status')) +draft = doc_info.get('draft') +# Handle old-style draft/rc scheme +release_candidate = None if draft else doc_info.get('release_candidate') +if status: + if type(draft) is bool: + print("error: Mixing old-style doc_info.draft with doc_info.status") + draft = '<<draft>>' if draft else 0 + if release_candidate is not None: + print("error: Mixing old-style doc_info.release_candidate with doc_info.status. Ignoring rc") + draft = '<<rc{}>>'.format(release_candidate) +else: + # no new-style status has been set, determine from draft/rc + if release_candidate: + status = 'PRC' + draft = release_candidate + elif type(draft) is int: + # Mixing new-style draft sequencing with no status! + print("error: Document status value required") + status = '<<Status>>' + elif draft: + status = 'DFT' + draft = 1 + else: + status = 'PUB' + draft = 0 +# Enforce draft revision provided when required by status +if status in ('MEM','PUB'): + if type(draft) is int and draft > 0: + print("error: Release status must not have draft revision number") + draft = '<<{}>>'.format(draft) +else: + if not draft: + print("error: Non-release status must have draft revision number") + draft = '<<draft>>' + +status_full = full_status(status) + +status_watermark = { + 'DFT': 'DRAFT', + 'CRV': 'Review', + 'CPR': 'Review', + 'MRV': 'Review', + 'MPR': 'Review', + 'MRC': 'Candidate', + 'PRV': 'Review', + 'PPR': 'Review', + 'PRC': 'Candidate', +} +quality_watermark = { + 'DEV': 'Development', + 'ALP': 'ALPHA', + 'BET': 'BETA' +} +watermark = doc_info.get('watermark', + status_watermark.get(status, + quality_watermark.get(quality))) + +feedback = doc_info.get('feedback') +nowdate = now.strftime('%B %Y' if status == 'MEM' or status == 'PUB' else '%d/%m/%Y') +docdate = nowdate if status == 'DFT' else doc_info.get('date', nowdate) + +c_index = doc_info.get('identifier_index', True) +page_break = doc_info.get('page_break', template_info.get('page_break','appendix')) + +majorversion, minorversion = split_version(version) +extension = doc_info.get('extension_doc', None) +if extension: + if extension == True: + # Support previous syntax for this config item + extension = 'Extension' + version = '{} {}'.format(version, extension) + +# The full version, including alpha/beta/rc tags. +release, release_full, issue = make_release(version, quality, issue_no, draft) + +# Document filename +build_file = template_info.get('make_filename') +docname = build_file(doc_info, doc_id, fulltitle, release, status_full) if build_file else None +if not docname: + docname = project.lower() +docname = docname.replace(' ','_') + +# Build filename +filename = doc_info.get('filename', docname) + +# Copyright notice, default to author +copyright_text = doc_info.get('copyright', author) +copyright = ' {} {}'.format(copyright_date, copyright_text) + +# Create tags based on the content inclusion configuration + +include_content = set(doc_info.get('include_content',[])) + +if status == 'DFT': + include_content.update(['rationale', 'todo', 'banner', 'comment']) +elif status in ('CRV','CPR','MRV','MPR','PRV','PPR'): + include_content.update(['rationale', 'banner']) +elif status in ('MRC','PRC'): + include_content.update(['banner']) + +for option in include_content: + tags.add('include_{}'.format(option)) + +# Substitutions for use in source and latex documents + +doc_terms = { + 'docid': doc_id, # FPG + 'docfulltitle': fulltitle, # PG + 'docrsttitle': rsttitle, # P + 'dochtmltitle': htmltitle, # PG + 'doclatextitle': latextitle, # P + 'doctitle': title, # FPG + 'API': title, #AF + 'APIversion': version, #A P + 'docversion': version, # legacy usage + 'majorversion' : '``{}``'.format(majorversion), # F + 'minorversion' : '``{}``'.format(minorversion), # F + 'hexversion' : '``0x{:02X}{:02X}``'.format(majorversion, minorversion), # F + 'docquality': quality_full, # P + 'docissue': issue or str(issue_no), # P + 'docstatus': status_full, # G + 'docauthor': author, # PG + 'docdate': docdate, # P + 'docrelease': release, # G + 'docreleasefull': release_full, # FP + 'doccopyright': copyright, # PG + 'docowner': owner, # P + 'docconfidentiality': 'Non-confidential', + 'docfeedback': feedback, # PG + 'docwatermark': watermark, # PG + 'docchapterbreak': ('1' if page_break == 'chapter' else ''), # PG + 'docappendixbreak': ('1' if page_break == 'appendix' else ''), # PG +} +# Filter out any missing or empty items +doc_terms = dict((k,v) for k,v in doc_terms.items() if v is not None and v != '') +# Add any extra terms from the template +for fd in template_info.get('terms', {}).items(): + doc_terms[fd[0]] = fd[1].format(**doc_terms) +# Add any formatted terms from the template +for fd in template_info.get('formatted_terms', {}).items(): + tag = fd[0] + data = fd[1] + doc_terms[tag] = f':{tag}:`{data}`'.format(**doc_terms) + +logo_file = template_info['logo_file'] + +# -- psa-api-tool extension configuration -------------------------------------- + +primary_domain = 'psa_c' + +psa_api_license = doc_info.get('license', 'missing') + +psa_api_c_header = doc_info.get('header', filename) + +psa_api_retval_order = doc_info.get('error_order',[]) + +psa_api_header_doxygen = doc_info.get('header_doxygen', 0) + +psa_api_front_sections = template_info.get('front_sections',[]) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.todo', + 'sphinx.ext.graphviz', + 'psa-api-tool' +] + +try: + if importlib.util.find_spec('sphinxext.opengraph') is not None: + # Configuration for opengraph metadata + ogp_site_url = '{{ site.url }}/' + ogp_site_name = '{} {}'.format(fulltitle, version) + extensions.append('sphinxext.opengraph') +except ModuleNotFoundError: + pass + +# Add any paths that contain templates here, relative to this directory. +templates_path = [os.path.join(psa_api_template_path,'sphinx-templates')] + +# The suffix(es) of source filenames. +source_suffix = {'.rst': 'restructuredtext'} + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +#language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +#exclude_patterns = [] + +# Custom roles for specifications +roles = ['sc', 'issue'] + [k for k in template_info.get('formatted_terms',{})] +# Additional common substitutions +terms = { + 'impdef': ':sc:`implementation defined`', + } + +prolog = ['.. |br| raw:: html','',' <br />'] +prolog += ['.. role:: {}'.format(r) for r in roles] +prolog += ['.. |{}| replace:: {}'.format(k, v) for k,v in terms.items()] +prolog += ['.. |{}| replace:: {}'.format(k, subst_rst(v)) for k,v in doc_terms.items()] +prolog += ['.. include:: {}'.format(fn) for fn in doc_info.get('prolog_files',[])] +if watermark: + prolog += ['.. only:: html','',' .. container:: watermark','',' |docwatermark|',''] +rst_prolog = '\n'.join(prolog) + '\n\n' + +# The reST default role (used for this markup: `text`) to use for all +# documents. +default_role = 'any' + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# If true, keep warnings as "system message" paragraphs in the built documents. +keep_warnings = True + +# Use a 'todo' in the include_content to indicate if TODOs are processed +todo_include_todos = ('todo' in include_content) + +# Hide the source file name in the 'todolist' +todo_link_only = True + +highlight_language = 'none' + +# Number figures and tables, using the whole document scope +numfig = True +numfig_secnum_depth = template_info.get('numfig_sec_depth', 0) +numfig_format = { + 'figure': 'Figure %s', + 'table': 'Table %s', + 'code-block': 'Listing %s', + 'section': '§%s' +} + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = template_info.get('html_theme', 'alabaster') + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +html_theme_options = { + 'fixed_sidebar': True, +} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. +html_title = '{} {}'.format(fulltitle, version) + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +html_logo = os.path.join(psa_api_template_path,logo_file+'.svg') + +html_css_files = template_info['html_css_files'] + +# The name of an image file (relative to this directory) to use as a favicon of +# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = [os.path.join(psa_api_template_path, 'html-static')] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +html_sidebars = { + '**': ['toc.html', 'indextoc.html', 'searchbox.html'], +} + +# A dictionary of values to pass into the template engine’s context for all +# pages. +html_context = doc_terms + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +html_domain_indices = c_index +if not c_index: + html_sidebars['**'].remove('indextoc.html') + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, the reST sources are included in the HTML build as _sources/name. +html_copy_source = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +html_show_sphinx = False + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a <link> tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr' +#html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# Now only 'ja' uses this config value +#html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +#html_search_scorer = 'scorer.js' + +# Suffix for section numbers in HTML output. This removes trailing '.' +html_secnumber_suffix = ' ' + +# -- Options for LaTeX output --------------------------------------------- + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, filename+'.tex', fulltitle, author, 'manual'), +] + +# Appendices are indicated in PSA API specifications using the .. appendix:: toctree +latex_appendices = [] + +latex_additional_files = [os.path.join(psa_api_template_path, 'psa-api-tool.sty')] +if 'latex_files' in template_info: + latex_additional_files += [os.path.join(psa_api_template_path, f) for f in template_info['latex_files']] + +# Construct the latex preamble +# Define all the project info used for the title page and footer +latex_preamble = ['\\def\\{}{{{}}}'.format(k,subst_latex(v)).replace('&','\\&') for k,v in doc_terms.items()] +# Include the PSA API-specific styling and content +latex_preamble += [r'\input{psa-api-tool.sty}'] +# Improve all the code blocks if sphinx version supports it +latex_preamble += [r'\useverbatimfortt'] + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). + 'papersize': 'a4paper', + 'maketitle': r'',#r'\psamaketitle', + 'tableofcontents': r'', + +# The font size ('10pt', '11pt' or '12pt'). + 'pointsize': template_info['latex_pointsize'], + +# font package: use the fonts specified in the template info, this should include any necessary \usepackage commands + 'fontpkg': '\n'.join(template_info['latex_fonts']), + +# Include the PAS API specification definitions and preamble. + 'preamble': '\n'.join(latex_preamble), + +# Latex figure (float) alignment + 'figure_align': '!ht', + +# Other configuration + 'sphinxsetup': ','.join(template_info['latex_sphinxsetup']), + +# Fix issue with mismatched flags when including textcomp package +# See https://github.com/sphinx-doc/sphinx/issues/4727#issuecomment-372096951 +# Underlying issue is fixed in Sphinx 1.7.2, but this is harmless + 'passoptionstopackages': ''' +\\PassOptionsToPackage{warn}{textcomp} +\\PassOptionsToPackage{linktocpage=true}{hyperref} +''', + +# remove blank pages between chapters + 'extraclassoptions': 'openany,oneside', + +# Keep the chapter titles simple + 'fncychap': '', +} + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +latex_logo = os.path.join(psa_api_template_path, logo_file+'.pdf') + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# If false, no module index is generated. +latex_domain_indices = c_index + +# Set the standard table format for specifications. Individual tables can override +latex_table_style = template_info['latex_table_style'] + +#-- Options for graphviz extension ---------------------------------------- + +# Use SVG for html output, not PNG +graphviz_output_format = 'svg' + +# Set the font used for graphviz diagrams +graphviz_dot_args = template_info['graphviz_dot_args'] + +#-- Options for mathjax --------------------------------------------------- + +mathjax3_config = template_info['mathjax3_config'] diff --git a/tools/psa-api-tool.py b/tools/psa-api-tool.py new file mode 100644 index 00000000..f1f6237e --- /dev/null +++ b/tools/psa-api-tool.py @@ -0,0 +1,2628 @@ +# SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +# SPDX-License-Identifier: Apache-2.0 + +import os.path +import re +import string +import textwrap +from collections import namedtuple +from operator import attrgetter +from typing import cast + +import sphinx.builders +import sphinx.directives.code +import sphinx.domains +import sphinx.environment +from docutils import nodes +from docutils.parsers.rst import directives +from sphinx import addnodes +from sphinx.directives.other import Include, TocTree +from docutils.parsers.rst.directives.tables import RSTTable +from sphinx.roles import XRefRole +from sphinx.util.nodes import make_refnode +from sphinx.util.docutils import SphinxRole, SphinxDirective +from sphinx.util.docutils import new_document + +logger = sphinx.util.logging.getLogger(__name__) + +def clean_dir(path): + # Remove all files at the path and in subdirectories + # Does not delete the directories themselves + for the_file in os.listdir(path): + file_path = os.path.join(path, the_file) + if os.path.isfile(file_path): + os.unlink(file_path) + elif os.path.isdir(file_path): + clean_dir(file_path) + +_nested_parentheses_rs = r'(?:[^()]|\((?:[^()]|\([^()]*\))*\))*' +_nested_parentheses_re = re.compile(r'\s*\(({})\)\Z' + .format(_nested_parentheses_rs)) +def c_name_from_prototype(prototype): + """Parse a C prototype and extract the name that it defines. + + This function supports most prototypes, but has a few limitations. + The following features of the C language are not supported: + * More than 3 levels of nested parentheses. + * Arrays. + * Functions or function pointers returning a function or function pointer. + """ + # Strip optional leading "typedef" and trailing ";" + prototype = re.sub(r'\s*;?\s*\Z', r'', prototype) + prototype = re.sub(r'\A\s*(?:typedef)?\s*', r'', prototype) + m = re.search(_nested_parentheses_re, prototype) + if m: + prototype = prototype[:m.start()] + m = re.search(_nested_parentheses_re, prototype) + if m: + prototype = m.group(1) + # Remove array subscript, or bitfield size + m = re.search(r'(\w+)(?:\[.*\]|\s*:\s*\d+)?\Z', prototype) + return m.group(1) + +def nodes_text(nodes): + return ''.join(n.astext() for n in nodes) + +def autolinking_literal(text, element = nodes.literal): + """Literal text with weak references. + + Return a list of inline nodes that together form ``text``. + Isolate each C identifier (or keyword) in ``text`` as its own node, + and make those nodes a weak reference. + + By default use nodes.literal for each element, but allow the caller + to provide an alternate node constructor as ``element``. + """ + parts = [] + cursor = 0 + for m in re.finditer(r'(0[xX][0-9A-Fa-f]*)|([A-Z_a-z][0-9A-Z_a-z]*)|(/\*.*?(?:\*/))|(/\*(?:.|\n|\r\n?)*?(?:\*/)|//.*?$)', text, re.M): + item = m[0] + if m[1]: + continue + elif m[2]: + # An identifier + xref = sphinx.addnodes.pending_xref(rawsource=item, + reftype='weak', + refdomain='psa_c', + reftarget=item) + xref += element(text=item) + elif m[3]: + # A special comment element in the prototype + # Convert to a possible hyperlink if the text of the comment + # is a link target + word = re.sub(r'[ _:;,-.+=#~\/!?*]+','-',item[3:-3]).lower() + rf = sphinx.addnodes.pending_xref(rawsource=word, + reftype='ref', + refdomain='std', + refexplicit=True, + reftarget=word) + rf += element(text=item) + xref = nodes.emphasis() + xref += rf + elif m[4]: + # A regular C comment + xref = nodes.emphasis(text=item) + if cursor < m.start(): + parts.append(element(text=text[cursor:m.start()])) + parts.append(xref) + cursor = m.end() + if cursor < len(text): + parts.append(element(text=text[cursor:])) + return parts + +def autolinking_literal_block(text): + """Literal text block with weak references. + + Return a nodes.literal_block containing auto-linked text. + """ + + # When a literal node is contained within a literal_block node, some + # output formats compose the two formats and result in a messy rendering. + # + # As this is already formatted as a literal_block, we only need to use + # Text blocks for the individual pieces of auto-linked text. + def text_element(text): + return nodes.Text(text) + + # Providing an explicit rawsource that is distinct from the content + # causes the highlighter to bail out and preserve the auto-linking xrefs + # + # The meaningless '<psa-autolink>' is used for this purpose, so that if the + # rawsource is used for debugging, it can still be identified in the + # source document. + block = nodes.literal_block( + rawsource="<psa-autolink>" + text + '</psa-autolink>', + language = "none") + block += autolinking_literal(text, element=text_element) + return block + +def role_autolink(name, rawtext, text, lineno, inliner, + options={}, content=[]): + return autolinking_literal(text), [] + +class PSACodeBlock(sphinx.directives.code.CodeBlock, SphinxDirective): + required_arguments = 0 # Override in case of using Sphinx <2.0 + optional_arguments = 1 # Override in case of using Sphinx <2.0 + + def run(self): + if not self.arguments or self.arguments[0] != 'xref': + # A standard sphinx code-block:: + return super().run() + + code = self.content.data + if 'linenos' in self.options or 'lineno-start' in self.options: + start = self.options.get('lineno-start',1) + nlines = len(code) + just = len(str(start + nlines -1)) + numbers = [str(start + n).rjust(just) for n in range(0, nlines)] + code = [l+' '+r for l,r in zip(numbers,code)] + return [autolinking_literal_block('\n'.join(code))] + +class PSACodeBlockInclude(sphinx.directives.code.LiteralInclude, SphinxDirective): + def run(self): + if 'language' not in self.options or self.options['language'] != 'xref': + # A standard sphinx literal-include:: + return super().run() + + # Use the literalinclude reader to implement the filtering options + + document = self.state.document + if not document.settings.file_insertion_enabled: + return [document.reporter.warning('File insertion disabled', + line=self.lineno)] + # convert options['diff'] to absolute path + if 'diff' in self.options: + raise ValueError('Cannot use "diff" option with "xref" language') + + try: + location = self.state_machine.get_source_and_line(self.lineno) + rel_filename, filename = self.env.relfn2path(self.arguments[0]) + self.env.note_dependency(rel_filename) + + reader = sphinx.directives.code.LiteralIncludeReader(filename, self.options, self.config) + text, lines = reader.read(location=location) + text = text.strip() + + if 'linenos' in self.options or 'lineno-start' in self.options: + code = text.split('\n') + start = reader.lineno_start + nlines = len(code) + just = len(str(start + nlines -1)) + numbers = [str(start + n).rjust(just) for n in range(0, nlines)] + code = [l+' '+r for l,r in zip(numbers,code)] + text = '\n'.join(code) + return [autolinking_literal_block(text)] + except Exception as exc: + return [document.reporter.warning(exc, line=self.lineno)] + + +# some raw latex nodes for document control + +def latexnode(latex, directive=None): + raw_node = nodes.raw('', text=latex, format = 'latex') + if directive: + raw_node.source, raw_node.line = directive.state_machine.get_source_and_line(directive.lineno) + return raw_node + +def latexnewpage(directive): + return latexnode(r'\clearpage', directive) + +def latexpageref(id, directive = None): + return latexnode('\\psapageref{{{}}}'.format(id), directive) + + +# .. rationale:: directive for Information blocks that only appear if the 'include_rationale' +# tag is defined. + +class Rationale(SphinxDirective): + optional_arguments = 1 + final_argument_whitespace = True # used if derived class take an argument + has_content = True + + def run(self): + # build an internal only box using the rationale class/environment + # If provided, the argument is the title, otherwise "Rationale" is used + if not self.arguments: + self.arguments = ['Rationale'] + title, m = self.state.inline_text('\n'.join(self.arguments), self.lineno) + titlebold = nodes.strong() + titlebold += title + titlenode = nodes.paragraph() + titlenode['classes'] += ['admonition-title'] + titlenode += titlebold + content = nodes.container(classes = ['rationale','admonition']) + content += titlenode + content += m + self.state.nested_parse(self.content, self.content_offset, content) + # now wrap this in an ``.. only:: include_rationale`` node + only = sphinx.addnodes.only(expr = 'include_rationale') + only += content + return [only] + +# .. comment:: directive for Information blocks that only appear if the 'include_comment' +# tag is defined. + +class Comment(SphinxDirective): +# optional_arguments = 1 +# final_argument_whitespace = True # used if derived class take an argument + has_content = True + + def run(self): + # build an internal only box using the comment class/environment + title, m = self.state.inline_text('Commentary', self.lineno) + titlebold = nodes.strong() + titlebold += title + titlenode = nodes.paragraph() + titlenode['classes'] += ['admonition-title'] + titlenode += titlebold + content = nodes.container(classes = ['comment','admonition']) + content += titlenode + content += m + self.state.nested_parse(self.content, self.content_offset, content) + # now wrap this in an ``.. only:: include_comment`` node + only = sphinx.addnodes.only(expr = 'include_comment') + only += content + return [only] + +# directives for main document templating and control + +class TemplateImage(directives.images.Image, SphinxDirective): + def run(self): + # locate image relative to the template directory, not the doc source + file = os.path.join(self.config.psa_api_template_path,self.arguments[0]) + # The image:: directive takes a URI, so need to replace OS + # path separators with URI path separators + self.arguments[0] = os.path.normpath(file).replace(os.path.sep, '/') + return super().run() + +class TitlePage(SphinxDirective): + """ The title page directive is the first thing in the main index file + If it has content, this is taken to be the abstract for the document + """ + required_arguments = 0 + has_content = True + option_spec = {} + + def stash_abstract(self, content): + item = { + 'content': content, + 'replace': True, + } + errors = [] + sections = self.env.domaindata['psa_c']['front-matter'] + if 'abstract' in sections: + e = 'Duplicate directive "{}". Also defined in {}.'.format( + 'abstract', sections['abstract'][0]) + errors.append(self.state_machine.reporter.warning(e, line = self.lineno)) + sections['abstract'] = (self.env.docname, item) + return errors + + def run(self): + messages = [] + source = self.state.document.current_source or self.get_source_info()[0] or '' + if self.content: + content = nodes.Element() + self.state.nested_parse(self.content, self.content_offset, content) + system_messages = [n for n in content.children if isinstance(n, nodes.system_message)] + abstract = [n for n in content.children if not isinstance(n, nodes.system_message)] + messages += system_messages + if abstract and 'abstract' in self.config.psa_api_front_sections: + messages += self.stash_abstract(abstract) + title_path = os.path.join(os.sep,self.config.psa_api_template_path,'title-page.rst') + lines = ['.. include:: ' + title_path] + self.state_machine.insert_input(lines, source) + return messages + +class PSATocTree(TocTree): + option_spec = { + 'numbered': directives.nonnegative_int, + 'maxdepth': directives.nonnegative_int, + } + + def run(self): + if self.html_numbered: + num = self.options.setdefault('numbered', self.default_numbered) + else: + num = self.options.pop('numbered', self.default_numbered) + self.options.setdefault('maxdepth', self.default_maxdepth) + numfig_depth = self.env.config.numfig_secnum_depth + fig_prefix = '' + if numfig_depth == 1: + fig_prefix = '\\thechapter-' + elif numfig_depth == 2: + fig_prefix = '\\thesection-' + prefix = [latexnode('\\psa{}{{{}}}{{{}}}'.format(self.kind, num-1, fig_prefix), self)] + toc = super().run() + if self.html_numbered and self.alpha_numbers: + toc[0][0]['alpha_numbers'] = True + return prefix + toc + +class FrontMatter(PSATocTree): + default_numbered = 0 + html_numbered = False # Do not number this in HTML formats, as is not sequential + default_maxdepth = 2 + kind = 'frontmatter' + +class MainToc(PSATocTree): + default_numbered = 3 + html_numbered = True + alpha_numbers = False + default_maxdepth = 3 + kind = 'main' + +class Appendix(PSATocTree): + default_numbered = 3 + html_numbered = True + alpha_numbers = True + default_maxdepth = 3 + kind = 'appendix' + +class About(Include, SphinxDirective): + required_arguments = 0 + final_argument_whitespace = False + option_spec = {} + + def run(self): + self.arguments = [os.path.join(os.sep,self.config.psa_api_template_path,'about-chapter.rst')] + return super().run() + +class IncludeLicense(Include, SphinxDirective): + required_arguments = 0 + final_argument_whitespace = False + option_spec = {} + + def run(self): + license_path = os.path.join(os.sep,self.config.psa_api_tool_path,'license') + license = self.config.psa_api_license + rel_filename, filename = self.env.relfn2path(license) + if not os.path.isfile(filename): + rel_filename = os.path.join(license_path,license.lower().replace('-','_')+'.rst') + _, filename = self.env.relfn2path(rel_filename) + error = [] + if not os.path.isfile(filename): + rel_filename = os.path.join(license_path,'missing.rst') + error = [self.state_machine.reporter.error( + 'Invalid or unknown license name/identifier "{}".'.format(license), + line=self.lineno)] + self.arguments = [rel_filename] + return super().run() + error + +class Collector(SphinxDirective): + """ Collect structured data + options are used for inlinable entries, and content is permitted for + one multi-line item. + When run this data is parsed and the dictionary is added to the + domain data under a key named after the collector. + Only one instance of each collected item allowed in the source + """ + final_argument_whitespace = True # used if derived class take an argument + content_as = 'content' + unparsed_options = () + + def stash(self, item): + error = None + name = self.name.split(":")[-1] + sections = self.env.domaindata['psa_c']['front-matter'] + if name in sections: + e = 'Duplicate directive "{}". Also defined in {}.'.format( + name, sections[name][0]) + error = self.state_machine.reporter.warning(e, line = self.lineno) + sections[name] = (self.env.docname, item) + return error + + def run(self): + data = {} + messages = [] + if len(self.arguments) > 0: + data[self.argument_as], m = self.state.inline_text('\n'.join(self.arguments), self.lineno) + messages += m + for k, v in self.options.items(): + if v is None: + data[k] = True + elif k in self.unparsed_options: + data[k] = v + else: + data[k], m = self.state.inline_text(v, self.lineno) + messages += m + if self.has_content: + content = nodes.Element() + self.state.nested_parse(self.content, self.content_offset, content) + data[self.content_as] = content.children + error = self.stash(data) + if error: + messages[0:0] = error + return messages + +class KeyedCollector(Collector): + """ Collected data is stashed in a dictionary instead of a list. + The data dictionary name is taken from the directive name. + Derived classes can specify a different attribute to use as + the key with id_key. + By default a unique seq number is used as the dictionary key + """ + id_key = None # attribute used as a key + + def stash(self, item): + name = self.name.split(":")[-1] + if self.id_key: + key = canonical_rfc(nodes_text(item[self.id_key])).lower() + item['id'] = nodes.make_id(self.id_key +'-' + key) + else: + # Use a unique key based on source document and line + key = '{}.{}'.format(self.env.docname, self.lineno) + + error = None + data = self.env.domaindata['psa_c'][self.id_key or name] + if key in data: + e = 'Duplicate item "{}" for directive "{}". Also defined in {}.'.format( + key, name, data[key][0]) + error = self.state_machine.reporter.warning(e, line = self.lineno) + data[key] = (self.env.docname, item) + return error + +def option_choice(option, values): + def option_check(argument): + if argument in values: + return argument + raise ValueError(':{}: must be one of ({}).'.format(option, ', '.join(values))) + return option_check + +class FrontSection(Collector): + option_spec = { + 'extend': directives.flag, + 'replace': directives.flag, + 'hide': directives.flag + } + has_content = True + + sections = [] + + @classmethod + def add_directives(cls, app): + cls.sections[0:0] = app.config.psa_api_front_sections + for sect in cls.sections: + app.add_directive(sect, cls) + + def stash(self, item): + name = self.name.split(":")[-1] + errors = [] + n = sum([1 for o in self.option_spec.keys() if o in item]) + if n == 0: + # no option provided + if not item['content']: + # No option provided, and no content. Treat as :hide: + item['hide'] = True + e = 'Empty directive "{}", treating as requesting :hide: option.'.format(name) + errors.append(self.state_machine.reporter.warning(e, line = self.lineno)) + else: + # default to replace + item['replace'] = True + elif n > 1: + e = 'Only specify one of the options (:' + e += ':, :'.join(self.option_spec.keys()) + e += ':) for directive "{}".'.format(name) + errors.append(self.state_machine.reporter.error(e, line = self.lineno)) + + error = super().stash(item) + if error: + errors.append(error) + return errors + + +class InsertFrontSection(SphinxDirective): + """ The argument is the section title + The section id to insert must be provided by the :section: option + The default section content follows. + + If the section is excluded by doc_info, then drop the section. + + If content is provided in the domain data, this replaces the default + content, unless the :extend: flag was set, when it is appended to the + default content. + + If the :break-after: flag is set a page break is made after the section. + + The :class: option wraps all the content in the specified class/environment. + + The :not-in-toc: flag will format this like a section title and content, + but does not use a proper section node and does not result in a TOC entry. + """ + required_arguments = 0 + optional_arguments = 1 # The heading for the section + final_argument_whitespace = True + option_spec = { + 'section': directives.unchanged_required, + 'break-after': directives.flag, + 'class': directives.class_option, + 'not-in-toc': directives.flag, + 'keep-if-empty': directives.flag, + } + has_content = True + + def new_section(self, raw, title): + # Create the container, either a true section or a holding List + # + textnodes, messages = self.state.inline_text(title, self.lineno) + if 'not-in-toc' in self.options: + # use a styled paragraph for the title + i = nodes.inline(title, '', classes = ['sectiontitle']) + i += textnodes + p = nodes.paragraph(title, '') + p += i + n = nodes.Element() + n += p + return n + else: + # Adapted from docutils new_subsection() + section_node = nodes.section(raw_source=raw) + titlenode = nodes.title(title, '', *textnodes) + name = nodes.fully_normalize_name(titlenode.astext()) + section_node['names'].append(name) + section_node += titlenode + section_node += messages + section_node.document = self.state.document + self.state.document.note_implicit_target(section_node, section_node) + return section_node + + def run(self): + result = [] + + name = self.options.get('section') + if name and name not in FrontSection.sections: + result.append(self.state_machine.reporter.error( + 'Section "{}" not recognised for "insert-section::".'.format(name), + line = self.lineno)) + + _, item = self.env.domaindata['psa_c']['front-matter'].get(name, (None, {})) + + if item.get('hide'): + if not 'keep-if-empty' in self.options: + # Hide this section + return result + # Cannot hide a keep-if-empty section + result.append(self.state_machine.reporter.warning( + 'Cannot :hide: mandatory front section "{}".'.format(name), + line = self.lineno)) + + content = nodes.Element() + if not item.get('replace'): + self.state.nested_parse(self.content, self.content_offset, content) + if item.get('replace') or item.get('extend'): + content += item.get('content', []) + content = content.children + + if not content and not 'keep-if-empty' in self.options: + # Section is empty. Do not include it + return result + + if len(self.arguments) == 0: + self.options['not-in-toc'] = True + section_node = nodes.Element() + else: + section_node = self.new_section('\n'.join(self.content), self.arguments[0]) + + if 'class' in self.options: + section_node += nodes.container(nodes_text(content), + classes = self.options['class'], + *content) + else: + section_node += content + + if 'break-after' in self.options: + section_node.append(latexnewpage(self)) + + if 'not-in-toc' in self.options: + result.extend(section_node.children) + else: + result.append(section_node) + return result + +def resolve_references(node, docname, app): + # helper to resolve references in nodes created during deferred processing + document = new_document('') + document += node + app.env.resolve_references(document, docname, app.builder) + document.remove(node) + return node + +# .. banner:: and .. insert-banner:: directive for a title-page Information block +# that only appears if the 'include_banner' tag is defined. + +class banner(nodes.General, nodes.Element): + pass + +class Banner(Collector): + has_content = True + +class InsertBanner(SphinxDirective): + def run(self): + return [banner('')] + +def process_banner_nodes(app, doctree, docname): + _, data = app.env.domaindata['psa_c']['front-matter'].get('banner', (None,{})) + for node in doctree.traverse(banner): + if not app.builder.tags.has('include_banner') or not data.get('content'): + node.parent.remove(node) + continue + + banner_node = nodes.container(classes = ['banner','admonition']) + banner_node += data['content'] + banner_node = resolve_references(banner_node.deepcopy(), docname, app) + # build a box using the banner class/environment + node.replace_self(banner_node) + +class itemgetterornone: + def __init__(self, item): + self.item = item + + def __call__(self, obj): + return obj.get(self.item) + +class InsertTable(RSTTable, SphinxDirective): + # Base class that will consume data from Collector directives + option_spec = { + 'class': directives.class_option, + 'name': directives.unchanged_required, + } + optional_arguments = 1 + final_argument_whitespace = True + + def build_table(self, data, widths, keys=None, headers=None): + # Build a table node and preceeding colspec from the data of dictionary + # rows, given the structure defined. + # Either Headers or keys have to be provided to interpret the dictionary + # as columns. + # If no keys are provided, the headers are used lower-case as keys. + # Keys can either be strings, used directly in the dictionary, or callable + # functions that are invoked on the dictionary. + # Widths must match the number of columns in the headers/Keys + # + assert(keys or headers) + + keys = keys or [h.lower() for h in headers] + ncols = len(keys) + keys = [itemgetterornone(k) if isinstance(k, str) else k for k in keys] + + assert(widths and len(widths) == ncols) + assert(not headers or len(headers) == ncols) + + title_node, _ = self.make_title() + + table = nodes.table('', classes = self.options.get('class',[])) + self.set_source_info(table) + self.add_name(table) + if title_node: + table += title_node + + tgroup = nodes.tgroup(cols=ncols) + table += tgroup + table['classes'].append('colwidths-given') + for width in (widths): + tgroup += nodes.colspec(colwidth=width) + + if headers: + row = nodes.row() + for t in headers: + col = nodes.entry(t, nodes.paragraph(t, nodes.Text(t,t))) + row += col + thead = nodes.thead('', row) + tgroup += thead + + tbody = nodes.tbody() + for r in data: + row = nodes.row() + for k in keys: + v = k(r) + col = nodes.entry() + if v is not None: + if len(v) and isinstance(v[0], nodes.Text): # workaround early sphinx issue + v = nodes.paragraph(nodes_text(v), *v) + col += v + row += col + r['targetdoc'] = self.env.docname + tbody += row + tgroup += tbody + + return [table] if len(tbody) else [] + +class Release(KeyedCollector): + # Capture the information for a single document release, which is + # collated into the Release Information table + # + option_spec = { + 'date': directives.unchanged, + 'confidentiality': option_choice("confidentiality", ("Confidential", "Non-confidential")), + } + optional_arguments = 1 + argument_as = 'version' + content_as = 'change' + has_content = True + +class ReleaseTable(InsertTable): + def run(self): + self.options['class'] = ['longtable'] # splits over pages better if section is not in its own page + + data = (release for _, release in self.env.domaindata['psa_c']['release'].values()) + return self.build_table(data, + headers = ('Date', 'Version', 'Change'), + widths = (4,3,13) + ) + +reference_kinds = ("normative", "informative") + +def canonical_rfc(text): + m = re.match(r'\ARFC([1-9][0-9]*)\Z', text, flags = re.I) + if m: + text = 'RFC ' + m.group(1) + return text + + +class Reference(KeyedCollector): + # Capture the information for a single referenced document, which is + # collated into the References table, and can be referred via the + # :cite: and :cite-ref: roles. + option_spec = { + 'doc_no': directives.unchanged_required, # legacy alias for doc_id + 'doc_id': directives.unchanged_required, + 'author': directives.unchanged_required, + 'title': directives.unchanged_required, + 'publication': directives.unchanged_required, + 'url': directives.uri, + 'kind': option_choice("kind", reference_kinds), + } + required_arguments = 1 + argument_as = 'cite' + has_content = False + id_key = 'cite' + unparsed_options = ('kind',) + default_kind = 'normative' + + def stash(self, item): + errors = [] + # Move legacy 'doc_no' option to the current 'doc_id', without overriding + if 'doc_no' in item: + doc_no = item.pop('doc_no') + if 'doc_id' in item: + e = "Both 'doc_id' and 'doc_no' specified, ignoring 'doc_no'" + errors.append(self.state_machine.reporter.warning(e, line = self.lineno)) + else: + item['doc_id'] = doc_no + item.setdefault('kind', self.default_kind) + error = super().stash(item) + if error: + errors.append(error) + return errors + +class ReferenceTable(InsertTable): + option_spec = InsertTable.option_spec.copy() + option_spec['filter'] = option_choice("filter", ("arm", "non-arm", "with-id", "without-id", "none")) + option_spec['kind'] = option_choice("kind", reference_kinds + ("all",)) + option_spec['layout'] = option_choice("layout", ("by-ref", "by-id")) + option_spec['sorted'] = directives.flag + + @staticmethod + def resolve_ref(env, ref): + # Called during Xref resolution. The Reference table has already been inserted + # so the target document for the citation is known + data = env.domaindata['psa_c']['cite'] + if ref not in data: + return '', '', '' + _, item = data[ref] + return item.get('targetdoc',''), item['id'], item.get('title','') + + @staticmethod + def make_reference_target(reference): + para = nodes.paragraph() + para += nodes.target('', ids = [reference['id']]) + para += nodes.Text('[{}]'.format(nodes_text(reference['cite']))) + return para + + @staticmethod + def make_reference_content(reference): + para = nodes.paragraph() + if 'title' in reference: + if 'author' in reference: + para += reference['author'] + para += nodes.Text(', ') + para += nodes.emphasis('',*reference['title']) + if 'publication' in reference: + para += nodes.Text(', ') + para += reference['publication'] + para += nodes.Text('. ') + if 'url' in reference: + ref = reference['url'][0] + if not isinstance(ref, nodes.reference): + ref = nodes.reference(text=ref, refuri='https://' + ref) + para += [ref] + return para + + @staticmethod + def make_id_reference_specification(reference): + para = nodes.paragraph() + para += reference.get('doc_id', reference['cite']) + return para + + keys3 = [make_reference_target.__func__, 'doc_id', make_reference_content.__func__] + keys2 = [make_reference_target.__func__, make_reference_content.__func__] + keys_by_id = [make_id_reference_specification.__func__, + make_reference_content.__func__, + make_reference_target.__func__] + + def run(self): + self.options['class'] = ['longtable'] # tabulary formats targetted cells badly + + layout = self.options.get('layout', 'by-ref') + if layout == 'by-id': + keys = self.keys_by_id + headers = ['Standard / Specification', 'Description', 'Ref'] + widths = (6,14,4) + else: + keys = self.keys3 + headers = ['Ref', 'Document Number', 'Title'] + widths = (4,4,13) + + filter = self.options.get('filter','none') + if filter == 'arm': + filter = 'with-id' + elif filter == 'non-arm': + filter = 'without-id' + if layout == 'by-ref' and filter == 'without-id': + keys = self.keys2 + headers.pop(1) + widths = (widths[0],sum(widths[1:])) + + kind = self.options.get('kind', 'all') + data = self.env.domaindata['psa_c']['cite'] + def data_iter(): + ids = data.keys() + if 'sorted' in self.options: + ids = sorted(ids) + + for id in ids: + _, item = data[id] + if filter == 'with-id' and not 'doc_id' in item: + continue + if filter == 'without-id' and 'doc_id' in item: + continue + if kind != 'all' and kind != item['kind']: + continue + yield item + + return self.build_table(data_iter(), + headers = headers, + widths = widths, + keys = keys + ) + +def role_cite(name, rawtext, text, lineno, inliner, + options={}, content=[]): + target = text.lower() + ref = sphinx.addnodes.pending_xref(rawsource = rawtext, + refdomain = 'psa_c', + reftype = name, + reftarget = target, + refwarn = True, + support_smartquotes=False + ) + ref += nodes.inline(text, '[{}]'.format(text)) + return [ref], [] + +class Term(KeyedCollector): + # Capture the information for a single glossary term + # + option_spec = { + 'abbr': directives.unchanged_required, + } + required_arguments = 1 + final_argument_whitespace = True + argument_as = 'term' + has_content = True + content_as = 'definition' + id_key = 'term' + + def stash(self, item): + typ = self.name.split(':')[-1] + cls = ['sc'] if typ == 'scterm' else [] + item['cls'] = cls + a_error = None + if typ == 'abbr': + item['isabbr'] = True + elif 'abbr' in item: + # Add extra term for the abbreviation + term = nodes_text(item['term']) + defn = nodes.paragraph(':{}:`{}`'.format(typ, term)) + defn += role_term(typ, ':{}:`{}`'.format(typ, term), term, 0, None)[0] + dabbr = {'term': item['abbr'], 'definition' : [defn], 'cls' : cls, 'isabbr': True } + a_error = super().stash(dabbr) + t_error = super().stash(item) + if not t_error: + return a_error + elif not a_error: + return t_error + else: + return [t_error, a_error] + +term_kinds = ("terms", "abbreviations") + +class TermTable(InsertTable): + option_spec = InsertTable.option_spec.copy() + option_spec['sorted'] = directives.flag + option_spec['kind'] = option_choice("kind", term_kinds + ("all",)) + + @staticmethod + def resolve_ref(env, ref): + # Called during Xref resolution. The Term table has already been inserted + # so the target document for the citation is known + data = env.domaindata['psa_c']['term'] + if ref not in data: + return '', '' + _, item = data[ref] + return item.get('targetdoc',''), item['id'] + + @staticmethod + def make_term_target(term): + para = nodes.paragraph() + para += nodes.target('', ids = [term['id']]) + tnode = nodes.inline(nodes_text(term['term']), classes = term['cls'], *term['term']) + if 'abbr' in term: + tnode += nodes.Text(' (') + tnode += term['abbr'] + tnode += nodes.Text(')') + para += tnode + return para + + keys = [make_term_target.__func__, 'definition'] + + def run(self): + self.options['class'] = ['longtable'] # tabulary formats targetted cells badly + + kind = self.options.get('kind', 'all') + if kind == 'abbreviations': + headers = ('Abbreviation','Meaning') + else: + headers = ('Term','Definition') + + data = self.env.domaindata['psa_c']['term'] + def data_iter(): + ids = data.keys() + if 'sorted' in self.options: + ids = sorted(ids) + + for id in ids: + _, item = data[id] + if kind == 'terms' and 'isabbr' in item: + continue + if kind == 'abbreviations' and not 'isabbr' in item: + continue + yield item + + return self.build_table(data_iter(), + headers = headers, + widths = (1,3), + keys = self.keys + ) + +def role_term(name, rawtext, text, lineno, inliner, + options={}, content=[]): + target = text.lower() + ref = sphinx.addnodes.pending_xref(rawsource = rawtext, + refdomain = 'psa_c', + reftype = name, + reftarget = target, + refwarn = True, + support_smartquotes=False + ) + ref += nodes.inline(text, text) + return [ref], [] + +ref_role = XRefRole(warn_dangling=True, innernodeclass = nodes.inline) + +def role_secref(name, rawtext, text, lineno, inliner, + options={}, content=[]): + return ref_role('psa_c:secref', rawtext, text, lineno, inliner, options, content) + +def role_numref(name, rawtext, text, lineno, inliner, + options={}, content=[]): + return ref_role('psa_c:numref', rawtext, text, lineno, inliner, options, content) + +def role_rfc(role, rawtext, text, lineno, inliner, options={}, content=[]): + # Link this into the citation/references scheme used by PSA template + # :rfc:`nnnn` -> :cite-title:`RFCnnnn` + # The cite-reference would link to an entry for the RFC in the References + # table. + # :rfc:`nnnn#x.y` -> :rfc:`nnnn` >§x.y< + # :rfc:`nnnn#Z` -> :rfc:`nnnn` >Appendix Z< + # The section/appendix link would be a hyperlink to the online copy of + # the RFC section/appendix + # + url_template = inliner.document.settings.rfc_base_url + inliner.rfc_url + m = re.match(r'\A(?P<num>[1-9][0-9]*)(?:#(?P<section>.*))?\Z', text) + if not m: + msg = inliner.reporter.error( + 'RFC number must be a number greater than or equal to 1; ' + f'"{text}" is invalid.', line=lineno) + prb = inliner.problematic(rawtext, rawtext, msg) + return [prb], [msg] + + rfc = m.group('num') + ret, _ = role_cite(role.lower().replace('rfc','cite'), rawtext, f'RFC {rfc}', lineno, inliner, **options) + + url = url_template % int(m.group('num')) + section = m.group('section') + if section: + ret.append(nodes.Text(' ')) + if section[0].isdigit(): + url += f'#section-{section}' + title = f'§{section}' + else: + url += f'#appendix-{section}' + title = f'Appendix {section}' + ret.append(nodes.reference(rawtext, title, refuri=url, **options)) + return ret, [] + +def role_url(name, rawtext, text, lineno, inliner, + options={}, content=[]): + target = text + if '//' not in target: + target = f'https://{target}' + ref = nodes.reference(rawtext, text=text, refuri = target) + return [ref], [] + +sra_elements = { + 'deployment-model': 'dm', + 'adversarial-model': 'am', + 'security-goal': 'sg', + 'threat': 't', + 'mitigation': 'm', +} + +def canonical_sra_id(typ, text): + typ = typ.split(':')[-1] + typ = sra_elements.get(typ, typ) + typ = typ.upper() + '.' + if text.upper().startswith(typ): + text = text[len(typ):] + return typ + text + +# role for SRA references +def role_sra_ref(name, rawtext, text, lineno, inliner, + options={}, content=[]): + text = canonical_sra_id(name, text) + ref = sphinx.addnodes.pending_xref(rawsource = rawtext, + refdomain = 'psa_c', + reftype = name, + reftarget = text, + refwarn = True, + support_smartquotes=False + ) + ref += nodes.inline(text, text) + return [ref], [] + +class SRADefinition(SphinxRole): + # role for SRA definitions + @staticmethod + def resolve_ref(env, ref): + # Called during Xref resolution. + # Return document, and definition label, or None if not present + return env.domaindata['psa_c']['sra'].get(ref, (None, None)) + + def run(self): + # canonicalise the text + text = canonical_sra_id(self.name, self.text) + key = nodes.make_id(text) + + data = self.env.domaindata['psa_c']['sra'] + error = [] + if key in data: + e = 'Duplicate SRA item "{}" for directive "{}". Also defined in {}.'.format( + text, self.name, data[key][0]) + error.append(self.inliner.reporter.warning(e, line = self.lineno)) + data[key] = (self.env.docname, text) + + node = [ + nodes.target('', ids = ['sra-' + key]), + nodes.inline(self.rawtext, text, classes=['sradef']) + ] + return node, error + +psa_roles = { + 'code': role_autolink, + 'cite': role_cite, + 'cite-title': role_cite, + 'term': role_term, + 'scterm': role_term, + 'rfc': role_rfc, + 'rfc-title': role_rfc, + 'secref': role_secref, + 'numref': role_numref, + 'url': role_url, + # SRA roles + 'deployment-model': SRADefinition(), + 'dm': role_sra_ref, + 'adversarial-model': SRADefinition(), + 'am': role_sra_ref, + 'security-goal': SRADefinition(), + 'sg': role_sra_ref, + 'threat': SRADefinition(), + 't': role_sra_ref, + 'mitigation': SRADefinition(), + 'm': role_sra_ref, +} +psa_directives = { + 'code-block': PSACodeBlock, + 'literalinclude': PSACodeBlockInclude, + 'rationale': Rationale, + 'comment': Comment, +} + +class ThreatData: + def __init__(self, DMs): + # set of deployment models specified in threat:: option + self.DMs = DMs + # Threat definition + self.data = {} + +class ThreatSubitem(SphinxDirective): + @property + def threat(self): + return self.env.domaindata['psa_threat']['local'] + + @property + def subitem(self): + return self.name.split(':')[-1] + +class ThreatElement(ThreatSubitem): + # Process a general element in a threat definition + has_content = True + + def run(self): + self.assert_has_content() + if self.subitem in self.threat.data: + raise self.warning('Directive "{}" already provided for this threat.'.format(self.subitem)) + container = nodes.Element() + self.state.nested_parse(self.content, self.content_offset, container) + self.threat.data[self.subitem] = container.children + return [] + +class ThreatRisk(ThreatSubitem): + # Process a risk element in a threat definition + optional_arguments = 1 + final_argument_whitespace = True + option_spec = { + 'impact': directives.unchanged_required, + 'likelihood': directives.unchanged_required, + 'risk': directives.unchanged + } + has_content = False + risk_abbr = {'VL': 'Very Low', 'L': 'Low', 'M': 'Medium', 'H': 'High', 'VH': 'Very High'} + risk_ix = {'Very Low': 0, 'Low': 1, 'Medium': 2, 'High': 3, 'Very High': 4} + risk_matrix = ( # by likelihood, then impact + ('Very Low' , 'Very Low' , 'Very Low' , 'Low' , 'Low' ), + ('Very Low' , 'Very Low' , 'Low' , 'Low' , 'Medium' ), + ('Very Low' , 'Low' , 'Medium' , 'Medium' , 'High' ), + ('Low' , 'Low' , 'Medium' , 'High' , 'Very High'), + ('Low' , 'Medium' , 'High' , 'Very High', 'Very High') + ) + + def parse_risk(self, risk): + risk = self.risk_abbr.get(risk, risk) + textnodes, messages = self.state.inline_text(risk, self.lineno) + p = nodes.paragraph(nodes_text(textnodes)) + p += textnodes + p += messages + return risk, p + + @staticmethod + def overall_risk(impact, likelihood): + impact_ix = ThreatRisk.risk_ix.get(impact) + likelihood_ix = ThreatRisk.risk_ix.get(likelihood) + if impact_ix is None or likelihood_ix is None: + return ':issue:`N/A`' + return ThreatRisk.risk_matrix[likelihood_ix][impact_ix] + + def get_element(self, content, n, default=None): + t, content[n] = self.parse_risk(self.options.get(n, default)) + return t + + def run(self): + DM = self.arguments[0].strip() if self.arguments else '' + content = {} + impact = self.get_element(content, 'impact') + likelihood = self.get_element(content, 'likelihood') + self.get_element(content, 'risk', + self.overall_risk(impact, likelihood)) + + if DM not in self.threat.DMs: + self.threat.DMs.append(DM) + for k, v in content.items(): + term = '-'.join((self.subitem, k)) + self.threat.data.setdefault(term, {})[DM] = v + return [] + +class ThreatDomain(sphinx.domains.Domain): + """Description of a Threat in a PSA SRA document.""" + name = 'psa_threat' + label = 'PSA Threat' + directives = { + 'description': ThreatElement, + 'adversarial-model': ThreatElement, + 'security-goal': ThreatElement, + 'unmitigated': ThreatRisk, + 'mitigations': ThreatElement, + 'residual': ThreatRisk, + } + directives.update(psa_directives) + roles = psa_roles + + def __init__(self, env, data): + super().__init__(env) + self.data['local'] = data + +def comma_list(s): + return [x.strip() for x in s.split(',')] + +class Threat(SphinxDirective): + """Process a Threat definition. + + This must have at least one of a Threat Id (specified using :id: option), and/or + a Threat title, specified as the argument to the directive. + + If :deployments: are specified, this is the number of deployments for which + risks are defined. + """ + has_content = True + optional_arguments = 1 + final_argument_whitespace = True + option_spec = { + 'id': directives.unchanged, + 'deployment-models': comma_list, + } + + @staticmethod + def finalize_DMs(threat): + if len(threat.DMs) > 1 or (len(threat.DMs)==1 and threat.DMs[0] != ''): + for dm in threat.DMs: + if len(dm.split())==1: + n, _ = role_sra_ref('psa_threat:dm', dm, dm, None, None) + else: + n = nodes.inline(dm, dm, classes=['sraref']) + p = nodes.paragraph(dm, '') + p += n + threat.data.setdefault('deployment-model',{})[dm] = p + + @staticmethod + def value_or_na(n): + if not n: + na = 'N/A' + n = nodes.paragraph(na, '', nodes.Text(na)) + return n + + @staticmethod + def entry(n): + n = Threat.value_or_na(n) + return nodes.entry(nodes_text(n), n) + + @staticmethod + def std_item(threat, data): + return data + + @staticmethod + def risk_item(threat, data): + n_dm = len(threat.DMs) + if n_dm == 1: + # if we have a single DM, just output the item + return Threat.value_or_na(data.get(threat.DMs[0])) + else: + # if we have more than one DM, build a borderless, unpadded table + wrap = nodes.container('', classes=['riskrow']) + table = nodes.table('', classes = ['borderless', 'colwidths-given']) + #self.set_source_info(table) + tgroup = nodes.tgroup(cols = n_dm) + for _ in range(n_dm): + tgroup += nodes.colspec(colwidth = 1) + tbody = nodes.tbody() + row = nodes.row() + for dm in threat.DMs: + row += Threat.entry(data.get(dm)) + tbody += row + tgroup += tbody + table += tgroup + wrap += table + return wrap + + threat_card = { + 'adversarial-model': (std_item.__func__, 'Adversarial Model'), + 'security-goal': (std_item.__func__, 'Security Goal'), + 'deployment-model': (risk_item.__func__, 'Deployment Model'), + 'unmitigated-impact': (risk_item.__func__, 'Unmitigated Impact'), + 'unmitigated-likelihood': (risk_item.__func__, 'Unmitigated Likelihood'), + 'unmitigated-risk': (risk_item.__func__, 'Unmitigated Risk'), + 'mitigations': (std_item.__func__, 'Mitigating Actions'), + 'residual-impact': (risk_item.__func__, 'Residual Impact'), + 'residual-likelihood': (risk_item.__func__, 'Residual Likelihood'), + 'residual-risk': (risk_item.__func__, 'Residual Risk'), + } + + @staticmethod + def description(threat): + data = threat.data.get('description') + if not data: + return [] + + data[0].insert(0, nodes.inline(text = 'Description: ', classes=['sralabel'])) + return data + + @staticmethod + def item(threat, id): + if not id in threat.data: + return [] + + f, label = Threat.threat_card[id] + t_node = nodes.term(label) + t_node += nodes.paragraph(label, '', nodes.inline(label, label, classes=['sralabel'])) + d_node = nodes.definition() + d_node += f(threat, threat.data[id]) + return nodes.definition_list_item('', t_node, d_node) + + def threat_section(self, title): + # Prepare a section + section = nodes.section(raw_source='\n'.join(self.content)) + section.document = self.state.document + + # Add title, and provide a link target + textnodes, messages = self.state.inline_text(title, self.lineno) + title_node = nodes.title(title, '', *textnodes) + section['names'].append(nodes.fully_normalize_name(title_node.astext())) + section += title_node + section += messages + self.state.document.note_implicit_target(section, section) + return section + + def run(self): + title = [] + if 'id' in self.options: + title.append(':threat:`{}`'.format(self.options['id'])) + if self.arguments: + title.append(self.arguments[0]) + section = self.threat_section(': '.join(title)) + + threat = ThreatData(self.options.get('deployment-models',[])) + + original_domain = self.env.temp_data['default_domain'] + try: + self.env.temp_data['default_domain'] = ThreatDomain(self.env, threat) + self.state.nested_parse(self.content, self.content_offset, section) + finally: + self.env.temp_data['default_domain'] = original_domain + + self.finalize_DMs(threat) + + # Process the threat definition + section += self.description(threat) + + deflist = nodes.definition_list() + for id in self.threat_card: + deflist += self.item(threat, id) + if deflist.children: + section.append(nodes.container(nodes_text(deflist), classes = ['threat'], *[deflist])) + + # Finished: discard ref to content, which is now inside the node tree + threat.data = None + return [section] + +class C_SubItem(SphinxDirective): + """Common base class for subitems. + + A subitem is part of a list of descriptions that apply to a specific + aspect of an object, for example the return values or the parameters + of a function. + + The definition of the item must immediately follow on the directive line. + The description, if provided, can start on the next line if desired. + """ + + has_content = True + final_argument_whitespace = True + + @property + def desc_data(self): + return self.env.domaindata['psa_description']['local'] + + @property + def subitem(self): + return self.name.split(':')[-1] + + def parse_spec(self, spec): + """Parse the argument for a list sub-item directive. + + Return the item list, spec and head nodes for the definition. + """ + raise NotImplementedError + + def add_to_index(self, spec, node): + pass + + def parse_content(self): + """Parse a subitem and return the description nodes. + """ + container = nodes.Element() + self.state.nested_parse(self.content, self.content_offset, container) + return container.children + + def check_content(self, arg_required=True): + """ Check that content has been provided, and that the definition is + present on the directive line. + Trim the definition from the content ViewList and return the definition + text. + """ + self.assert_has_content() + if self.lineno == self.content_offset+1: + line1 = self.content[0].strip() + self.content.trim_start() + return line1 + if arg_required: + raise self.warning('Argument missing for directive "{}"'.format(self.subitem)) + return None + + def check_subitem_permitted(self): + """ + Check that a sub-item is permitted for the API element types + + The subitem must provide a set ``valid_in`` of items that it can be used in + """ + if self.desc_data.element.objtype not in self.valid_in: + raise self.warning('Directive "{}" not valid for API element "{}"'.format( + self.subitem, self.desc_data.element.objtype)) + + def add_target_and_index(self, name, target): + self.desc_data.element.add_target_and_index(name, target) + + def run(self): + """Default run method for list sub-item directives. + + Stash the parsed definition list item in the appropriate list. + """ + self.check_subitem_permitted() + list, spec, head_nodes = self.parse_spec(self.check_content()) + + term_node = nodes.term(nodes_text(head_nodes)) + term_node += nodes.paragraph(nodes_text(head_nodes), '', *head_nodes) + description = nodes.definition(self.block_text) + self.state.nested_parse(self.content, self.content_offset, description) + defn = nodes.definition_list_item(description.astext(), + term_node, description, spec=spec) + self.add_to_index(spec, defn) + list.append(defn) + return [] + +class C_Summary(C_SubItem): + + def run(self): + self.assert_has_content() + if self.desc_data.summary: + raise self.warning('Directive "{}" already provided.'.format(self.subitem)) + self.desc_data.summary = self.parse_content() + return [] + +class C_Subsection(C_SubItem): + option_spec = { 'top': directives.flag } + + def run(self): + title, content = self.state.inline_text(self.check_content(), self.lineno) + content += self.parse_content() + if 'top' in self.options: + self.desc_data.top_sections.append((title, content)) + else: + self.desc_data.bottom_sections.append((title, content)) + return [] + +class C_Output(C_SubItem): + valid_in = {'function'} + + def parse_spec(self, spec): + return self.desc_data.outputs, spec, [nodes.literal(text=spec)] + +class C_Param(C_SubItem): + valid_in = {'function','macro'} + + def parse_spec(self, spec): + name = c_name_from_prototype(spec) + return self.desc_data.parameters, spec, [nodes.literal(text=name)] + +class C_Return(C_SubItem): + valid_in = {'function','macro'} + + def run(self): + self.check_subitem_permitted() + if self.desc_data.returns: + raise self.warning('Directive "{}" already provided.'.format(self.subitem)) + self.desc_data.return_type = self.check_content(False) + self.desc_data.returns = self.parse_content() + return [] + +class C_Retval(C_SubItem): + valid_in = {'function','macro'} + + def parse_spec(self, spec): + return self.desc_data.retvals, spec, autolinking_literal(spec) + +class C_Field(C_SubItem): + valid_in = {'struct'} + + def parse_spec(self, spec): + name = c_name_from_prototype(spec) + return self.desc_data.fields, spec, [nodes.literal(text=name)] + +class C_EnumValue(C_SubItem): + valid_in = {'enum'} + add_to_index = True + + def parse_spec(self, spec): + return self.desc_data.values, spec, [nodes.literal(text=spec)] + + def add_to_index(self, spec, node): + m = re.match(r'(\w+)(?:\s*=\s*(.+?))?\Z', spec) + self.add_target_and_index(m.group(1), node) + +class DescriptionData: + def __init__(self, element): + + # The API element object + self.element = element + + # A summary of the API element + self.summary = None + + # A list of member specifications and definitions for an enum element + self.values = [] + # A list of member specifications and definitions for a struct element + self.fields = [] + # A list of parameter specifications and definitions for an API element + self.parameters = [] + # A list of output specifications and definitions for an API element + self.outputs = [] + + # A description of the return value for an API element + self.returns = [] + # The return type for a function or typedef API element + self.return_type = None + # A list of return values and descriptions for an API element + self.retvals = [] + + # Lists of additional description sections + self.top_sections = [] + self.bottom_sections = [] + + @staticmethod + def make_subtitle(title): + if isinstance(title, str): + return nodes.rubric(title, text=title) + else: + t = nodes.rubric(rawsource = nodes_text(title)) + t += title + return t + + @staticmethod + def make_list(elements): + if not elements: + return [] + deflist = nodes.container(nodes_text(elements), classes = ['apisubitem']) + deflist += nodes.definition_list(nodes_text(elements), *elements) + return [deflist] + + def finish_list(self, title_text, elements): + if not elements: + return [] + title = self.make_subtitle(title_text) + return [title] + self.make_list(elements) + + def sort_retvals(self): + # Use the configured ordering to prioritise the return values: + # 1. Return values that aren't a single identifier and aren't + # listed in the configuration. + # 2. Return values that are listed in the configuration. + # 3. Single identifiers that aren't listed in the configuration. + # + # If there is no configured order then output the list in source order + # + # data.retvals[] is a list of (node,value) tuples + # return a list of nodes + + retvals = self.retvals + if not retvals: + return [] + + order = self.element.env.app.config.psa_api_retval_order + if order: + priority = dict(zip(order,range(len(order)))) + def get_priority(spec): + p = priority.get(spec, -1) + if p < 0 and re.match(r'^[A-Z][A-Z0-9_]*$', spec): + p = len(order) + return p + retvals.sort(key=lambda rv: get_priority(rv['spec'])) + + # extract and return the list of sorted nodes + return retvals + + def finish_returns(self): + if not self.return_type and not self.retvals and not self.returns: + return [] + title = self.make_subtitle('Returns') + if self.return_type: + title += nodes.Text(': ') + title += autolinking_literal(self.return_type) + stuff = [title] + self.returns + stuff += self.make_list(self.sort_retvals()) + return stuff + + def finish_subsections(self, sections): + stuff = [] + if sections: + for (title, subsection) in sections: + stuff += [self.make_subtitle(title)] + stuff += subsection + return stuff + + def finish_top(self): + top = self.finish_list('Fields', self.fields) + top += self.finish_list('Values', self.values) + top += self.finish_list('Parameters', self.parameters) + top += self.finish_list('Outputs', self.outputs) + top += self.finish_returns() + top += self.finish_subsections(self.top_sections) + return top + + def finish_bottom(self): + return self.finish_subsections(self.bottom_sections) + +class DescriptionDomain(sphinx.domains.Domain): + """Description of an object in a PSA API document.""" + name = 'psa_description' + label = 'PSA description' + directives = { + 'field': C_Field, + 'output': C_Output, + 'param': C_Param, + 'return': C_Return, + 'retval': C_Retval, + 'value': C_EnumValue, + 'summary': C_Summary, + 'subsection': C_Subsection, + } + directives.update(psa_directives) + roles = psa_roles + + def __init__(self, env, element=None): + super().__init__(env) + self.data['local'] = DescriptionData(element) + +def make_c_target(name): + return 'c.' + name + +class C_Item(SphinxDirective): + """Base class for PSA C API objects. + + Subclasses must define: + + * A field ``kind`` that provides the typeset description of what kind + of object this is (e.g. type, struct, function, ...). + * A method ``prototype(name, desc_data)`` that returns a pair of + (str, node.Element) for the item, used between the header and the content. + """ + has_content = True + required_arguments = 0 + optional_arguments = 1 + option_spec = { + 'name': directives.unchanged, + 'header': directives.unchanged, + 'definition': directives.unchanged, + 'naked': directives.flag, + 'guard': directives.unchanged, + 'comment': directives.unchanged, + } + final_argument_whitespace = True + naked = False + + @staticmethod + def doxy_brief(nodes): + if not nodes: + return '' + s = nodes_text(nodes).replace('\n',' ') + fin = re.search(r'(\D\.\D|\d\.\D|\D\.\d)', s) # . but not x.y + if fin: + s = s[:fin.start() + 2] + return s + + @staticmethod + def doxy_para(intro, text, indent=3): + if text: + return textwrap.wrap(text, 80 - indent, + initial_indent=intro + ' ', + subsequent_indent=' '*(len(intro)+1)) + return [intro] + + @staticmethod + def doxy_comment(lines): + if lines: + c = '/**' + for l in lines: + c += '\n *' + if l: + c += ' ' + l + return c + '\n */\n' + return '' + + def doxy_summary(self): + if not self.desc_data.summary: + return [] + return self.doxy_para('@brief',self.doxy_brief(self.desc_data.summary)) + + def basic_prototype(self): + # Return an unannotated prototype for the API element + raise NotImplementedError + + def prototype(self, doxygen): + # Return an annotated prototype for the API element + # Default implementation prefixes an undecorated prototype with + # a summary of the API element. + # Override if more complex annotation is required + + proto, error = self.basic_prototype() + # Document the basic summary, input parameters, and return values + if doxygen>0: + doxy = self.doxy_summary() + if doxy and doxygen==2: + # Document parameters of the API + if self.desc_data.parameters: + items = [('@param ' + nodes_text(p[0]).strip(), self.doxy_brief(p[1])) + for p in self.desc_data.parameters] + width = max([len(i[0]) for i in items]) + doxy.append('') + for i in items: + doxy.extend(self.doxy_para(i[0].ljust(width),i[1])) + if self.desc_data.returns: + doxy.append('') + doxy.extend(self.doxy_para('@return',self.doxy_brief(self.desc_data.returns))) + if doxy: + proto = '\n' + self.doxy_comment(doxy) + proto + if self.guard: + proto = '#ifndef {}\n{}\n#endif'.format(self.guard, proto) + if self.comment: + lines = textwrap.wrap(self.comment, 80 - 3, + initial_indent='/* ', subsequent_indent=' ') + proto = '\n'.join(lines) + '\n */\n' + proto + return proto, error + + def annotate_members(self, items, item_sep, final_sep, doxygen): + # Annotated prototypes for structs and enums, documenting each member + begin = '{} {} {{'.format(self.kind, self.item_name) + if 'type' in self.options: + begin = 'typedef ' + begin + end = '}} {};'.format(self.item_name) + else: + end = '};' + if not items: + proto = begin + end + else: + subitems = [] + for item in items: + brief = self.doxy_brief(item[1]) if doxygen==2 else '' + if brief: + brief = '\n /// '.join([''] + self.doxy_para('@brief', brief, 8)) + subitems.append(brief + '\n ' + item['spec']) + proto = begin + item_sep.join(subitems) + final_sep + '\n' + end + + if doxygen>0: + doxy = self.doxy_comment(self.doxy_summary()) + if doxy: + return '\n' + doxy + proto, None + return proto, None + + def parse_arguments(self): + # Either the API name must be the first line of argument, or it is + # provided using the `name` option. + # A macro definition can be provided as the subsequent lines of the + # directive argument body (before options), or using the `definition` + # option. + # The header for the API element can be specified as the `header` + # option, if not provided the current header in force for the source + # file will be used. + # Specific API element classes can extend this if required + argument_trail = None + if 'name' in self.options: + self.item_name = self.options['name'] + if self.arguments: + argument_trail = self.arguments[0] + elif self.arguments: + line_end = self.arguments[0].find('\n') + if line_end <= 0: + self.item_name = self.arguments[0] + else: + self.item_name = self.arguments[0][:line_end].rstrip() + argument_trail = self.arguments[0][line_end+1:] + else: + raise self.warning('API name missing for directive "{}"'.format(self.objtype)) + self.definition = self.options.get('definition', argument_trail) + self.header = self.options.get('header') + if 'naked' in self.options: + self.naked = True + self.guard = self.options.get('guard') + self.comment = self.options.get('comment') + if self.naked and self.definition: + raise self.warning('Naked API element "{}" cannot have a definition'.format(self.item_name)) + if self.naked and self.header: + raise self.warning('Naked API element "{}" cannot be added to a header'.format(self.item_name)) + + def add_target_and_index(self, name, node): + # for C API items we add a prefix since names are usually not qualified + # by a module name and so easily clash with e.g. section titles + targetname = make_c_target(name) + node['names'].append(targetname) + if targetname not in self.state.document.ids: + # If unique, use the exact target name as the id, not the output + # from nodes.make_id(). This maintains anchor name compatibility + node['ids'].append(targetname) + node['first'] = False + self.state.document.note_explicit_target(node) + inv = self.env.domaindata['psa_c']['elements'] + if name in inv: + self.state_machine.reporter.warning( + 'duplicate API definition of {}, other instance in {}.'.format( + name, self.env.doc2path(inv[name][0])), line=self.lineno) + inv[name] = (self.env.docname, self.objtype) + + def make_prototypes(self): + protos = [] + if not self.naked: + # construct the standard and annotated prototypes + proto, err = self.prototype(0) + header_proto, _ = self.prototype(self.config.psa_api_header_doxygen) + if err: + protos.append(err) + protos.append(autolinking_literal_block(proto)) + # Add the prototype to the list of API prototypes + self.env.domains['psa_c'].add_prototype(self.item_name, self.header, self.kind, + proto, header_proto, self.env.docname) + return protos + + def run(self): + env = self.env + + self.kind = self.objtype = self.name.split(':')[-1] + + self.parse_arguments() + # Prepare a section + section = nodes.section(raw_source=self.content) + section.document = self.state.document + section['objtype'] = self.objtype + + title_node = nodes.title() + title_node += nodes.literal(text=self.item_name) + title_node += nodes.Text(' ({})'.format(self.kind)) + section += title_node + + self.add_target_and_index(self.item_name, section) + + original_default_domain = env.temp_data['default_domain'] + section_offset = len(section) + desc_domain = DescriptionDomain(env, self) + self.desc_data = desc_domain.data['local'] + description = nodes.Element() + try: + env.temp_data['default_domain'] = desc_domain + self.state.nested_parse(self.content, self.content_offset, description) + finally: + env.temp_data['default_domain'] = original_default_domain + # Insert optional summary paragraph immediately after the title + if self.desc_data.summary: + section += self.desc_data.summary + # Add prototype + section += self.make_prototypes() + # Compile upper description sections + top = self.desc_data.finish_top() + section += top + # Add description + if description.children: + if top: + section.append(self.desc_data.make_subtitle('Description')) + section += description.children + # Add final subsections + section += self.desc_data.finish_bottom() + + # Finished + del desc_domain.data['local'] + return [section] + +class Attribute(C_Item): + naked = True + +class Typedef(C_Item): + def parse_arguments(self): + super().parse_arguments() + if re.match(r'\w+\Z', self.item_name): + self.definition = None + else: + self.definition = self.item_name + self.item_name = c_name_from_prototype(self.definition) + + def basic_prototype(self): + proto = self.definition + if proto is None: + proto = '/*...*/ ' + self.item_name + if not proto.startswith('typedef '): + proto = 'typedef ' + proto + if not proto.endswith(';'): + proto += ';' + return proto, None + +class Macro(C_Item): + version_opt = 'api-version' + option_spec = C_Item.option_spec + option_spec.update({ version_opt: option_choice(version_opt, ('major','minor','hex')) }) + formats = { + 'major': '{0}', + 'minor': '{1}', + 'hex' : '(0x{0:02X}{1:02X}u)' + } + + def basic_prototype(self): + error = None + definition = self.definition + if self.version_opt in self.options: + if definition: + error = self.state_machine.reporter.error( + 'Cannot provide definition for version macro "{}"'.format(self.item_name), + line=self.lineno) + elif self.desc_data.parameters: + error = self.state_machine.reporter.error( + 'Cannot provide arguments for version macro "{}"'.format(self.item_name), + line=self.lineno) + version = self.env.config.version.split()[0] + v = [int(x) for x in version.split('.')] + if len(v) == 1: + v.append(0) + definition = self.formats[self.options[self.version_opt]].format(*v) + elif definition is None: + definition = '/*...*/' + + if self.desc_data.parameters: + params = [p['spec'] for p in self.desc_data.parameters] + args = '(' + ', '.join(params) + ')' + else: + args = '' + # Very crude heuristic for line splitting. Needs work. + if len(self.item_name) + len(args) + len(definition) > 70: + proto = '#define {}{} \\\n {}'.format(self.item_name, args, definition) + else: + proto = '#define {}{} {}'.format(self.item_name, args, definition) + return proto, error + +class Function(C_Item): + option_spec = C_Item.option_spec + option_spec.update({ 'type': directives.flag }) # for function pointer typedefs + + def parse_arguments(self): + super().parse_arguments() + if 'type' in self.options: + self.kind = 'type' + + def basic_prototype(self): + if self.desc_data.return_type: + proto = self.desc_data.return_type + error = None + else: + proto = 'void' + # Issue a non-fatal error if no return type is specified + error = self.state_machine.reporter.warning( + 'No return type for function "{}", assuming void.'.format(self.item_name), + line=self.lineno) + + if 'type' in self.options: + proto = 'typedef ' + proto + ' (* ' + self.item_name + ')(' + self.kind = 'type' + else: + proto += ' ' + self.item_name + '(' + + if self.desc_data.parameters: + sep = ',\n' + ' ' * len(proto) + params = [p['spec'] for p in self.desc_data.parameters] + proto += sep.join(params) + else: + proto += 'void' + proto += ');' + + return proto, error + +class Struct(C_Item): + option_spec = C_Item.option_spec + option_spec.update({ 'type': directives.flag }) # for struct typedefs + + def prototype(self, doxygen): + return self.annotate_members(self.desc_data.fields, ';', ';', doxygen) + +class Enum(C_Item): + option_spec = C_Item.option_spec + option_spec.update({ 'type': directives.flag }) # for enum typedefs + + def prototype(self, doxygen): + return self.annotate_members(self.desc_data.values, ',', '', doxygen) + + +class PSA_C_Index(sphinx.domains.Index): + name = 'identifiers' + localname = 'Index of API elements' + shortname = 'API identifiers' + + @staticmethod + def entry_from_item(item): + return (item['name'], 0, item['docname'], item['target'], '', '', '') + + @staticmethod + def split_buckets(buckets, max_bucket_size): + """Split a bucket dictionary into smaller buckets. + + ``buckets`` is a dictionary whose keys are strings and whose values + are lists that satisfy the property that for each element ``entry`` in + ``buckets[key]``, ``key`` is a prefix of ``entry[0].upper()``. + + This function looks for keys whose value is a list of more than + ``max_bucket_size`` elements and splits the corresponding list by + moving each element to a key with a longer prefix. + """ + did_something = True + while did_something: + did_something = False + for key, entries in list(buckets.items()): + if len(buckets[key]) <= max_bucket_size: + continue + del buckets[key] + did_something = True + length = len(key) + 1 + for entry in entries: + new_key = entry[0].upper()[:length] + buckets.setdefault(new_key, []).append(entry) + + def collect_buckets(self): + entries = [] + for name, (doc, _) in list(self.domain.data['elements'].items()): + entries.append( (name, 0, doc, make_c_target(name), '', '', '') ) + if not entries: + return {} + + buckets = {'': entries} + if len(entries) >= 10: + self.split_buckets(buckets, len(entries) / 2) + return buckets + + def generate(self, docnames=None): + buckets = self.collect_buckets() + if not buckets: + return [], False + content = [(bucket, sorted(buckets[bucket])) + for bucket in sorted(buckets.keys())] + return content, False + +def option_list(option): + def option_check(argument): + if isinstance(argument, str): + return argument.replace(',',' ').split() + raise ValueError(':{}: must be a list of headers.'.format(option)) + + return option_check + +class Header(SphinxDirective): + required_arguments = 1 + final_argument_whitespace = True + option_spec = { + 'seq': directives.nonnegative_int, + 'guard': directives.unchanged, + 'include': option_list('include'), + 'system-include': option_list('system-include'), + 'c++': directives.flag, + 'copyright': directives.unchanged, + 'license': directives.unchanged, + } + has_content = True + + def run(self): + header = self.arguments[0].strip() + self.env.temp_data['header_file'] = header + self.env.temp_data['header_seq'] = self.options.pop('seq',0) + opt = self.options.copy() + if 'guard' in opt and not opt['guard']: + opt['guard'] = re.sub('[^a-zA-Z0-9]','_',header.upper()) + '_H' + opt['preamble'] = '\n'.join(self.content.data) + + if self.content.data or len(self.options) > 0: + collision = self.env.domains['psa_c'].add_header(header, opt) + if collision: + return [self.state_machine.reporter.error( + 'Duplicate header "{}" defined in source "{}".'.format( + header, collision), line = self.lineno)] + + return [] + +class header_node(nodes.General, nodes.Element): + pass + +class InsertHeader(SphinxDirective): + required_arguments = 1 + final_argument_whitespace = True + + def run(self): + # The generated header will depend on any source files with API elements + # in the header, and a source file that defines any adornments for the + # header. Tracking these does not ensure correct detection of every + # situation where this directive to be re-processed. The simplest + # reliable approach is to force this source file to always be re-read. + self.env.note_reread() + return [header_node('', header=self.arguments[0].strip())] + +def process_header_nodes(app, doctree, docname): + for node in doctree.traverse(header_node): + header = node['header'] + text = app.builder.env.domains['psa_c'].prototype_header(header, notice=False, doxy=False, db=False) + if not text: + logger.warning('Cannot insert header with no content: "%s"', + header, location=node) + inline_error = nodes.inline('', 'Header "{}" has no content'.format(header), + classes = ['issue']) + node.replace_self(inline_error) + else: + h = autolinking_literal_block(text) + node.replace_self(resolve_references(h, docname, app)) + +ApiElement = namedtuple('ApiElement', 'seq name type prototype annotated') + +class PSA_C_Domain(sphinx.domains.Domain): + """C language domain for PSA.""" + name = 'psa_c' + label = 'PSA C' + directives = { + 'enum': Enum, + 'function': Function, + 'macro': Macro, + 'struct': Struct, + 'typedef': Typedef, + 'attribute': Attribute, + 'header': Header, + 'insert-header': InsertHeader, + 'template-image': TemplateImage, + 'title': TitlePage, + 'front-matter': FrontMatter, + 'maintoc': MainToc, + 'appendix': Appendix, + 'about': About, + 'insert-section': InsertFrontSection, + 'banner': Banner, + 'insert-banner': InsertBanner, + 'include-license': IncludeLicense, + 'release': Release, + 'release-table': ReleaseTable, + 'reference': Reference, + 'reference-table': ReferenceTable, + 'term': Term, + 'scterm': Term, + 'abbr': Term, + 'term-table': TermTable, + 'threat': Threat, + } + directives.update(psa_directives) + roles = psa_roles + indices = [PSA_C_Index] + initial_data = { + 'prototypes': {}, # header -> { docname: [ApiElement] } + 'elements': {}, # name -> docname, objtype + 'headers': {}, # header -> docname, options + 'front-matter': {}, # section -> docname, content + 'cite': {}, # citeref -> docname, reference + 'term': {}, # term -> docname, definition + 'release': {}, # seq_id -> docname, release + 'sra': {}, # sra.id -> docname, None + } + + def clear_doc(self, docname): + for set in self.initial_data.keys(): + d = self.data[set] + if set == 'prototypes': + for header, elements in list(d.items()): + if docname in elements: + del elements[docname] + if not elements: + del d[header] + else: + for key, (fn, _) in list(d.items()): + if fn == docname: + del d[key] + + def merge_domaindata(self, docnames, otherdata): + for set in ('elements','headers','front-matter'): + d = self.data[set] + for key, (fn, data) in d.items(): + if fn in docnames: + d[key] = (fn, data) + + #if 'prototypes' in otherdata: + # self.data['prototypes'].update(otherdata['prototypes']) + + def get_objects(self): + for refname, (docname, type) in list(self.data['elements'].items()): + yield (refname, refname, type, docname, make_c_target(refname), 1) + + def add_prototype(self, name, header, type, prototype, annotated, docname): + if header is None: + header = self.env.temp_data.get('header_file', + self.env.config.psa_api_c_header) + seq = self.env.temp_data.get('header_seq',0) + sig = ApiElement(seq, name, type, prototype, annotated) + self.data['prototypes'].setdefault(header,{}).setdefault(docname,[]).append(sig) + + def sequenced_prototypes(self, header): + # Order the prototypes according to source sequence numbers. + # Sphinx partial rebuild results in variation in the order of + # the prototypes in the primary list. + # + p = sum(self.data['prototypes'].get(header,{}).values(),[]) + p.sort(key = attrgetter('seq')) + return p + + def sorted_prototypes(self, header): + # Sort the prototypes to enable accurate diffing of the API between + # versions of the documentation source code. Sphinx partial rebuild + # results in variation in the order of the prototypes in the primary + # list. + # + # The current ordering is by: + # - type, reversed so typedef, then macro, then function + # - API name + # + p = sum(self.data['prototypes'].get(header,{}).values(),[]) + p.sort(key = attrgetter('name')) + p.sort(key = attrgetter('type'), reverse = True) + return p + + def add_header(self, header, options): + # stash the extra header data + headers = self.data['headers'] + if header in headers: + return headers[header][0] + headers[header] = (self.env.docname, options) + return None + + def get_header_options(self, header): + h = self.data['headers'].get(header) + return h[1] if h else {} + + def prototype_header(self, header, notice, doxy, db): + # Output a string with the content for a specific header file + # If the header has no content then return None + if not header in self.data['prototypes']: + return None + + h = self.get_header_options(header) + lines = [] + postamble = [] + if notice: + # REUSE-IgnoreStart + if 'copyright' in h: + lines.append('// SPDX-FileCopyrightText: {}'.format(h['copyright'])) + if 'license' in h: + lines.append('// SPDX-License-Identifier: {}'.format(h['license'])) + # REUSE-IgnoreEnd + if lines: + lines.append('') + if not db: + if 'preamble' in h: + lines.extend([h['preamble'],'']) + guard = h.get('guard') + if guard: + lines.extend( ['#ifndef {}'.format(guard), '#define {}'.format(guard), ''] ) + postamble = ['','#endif // {}'.format(guard)] + includes = h.get('system-include',[]) + if includes: + for inc in includes: + lines.append('#include <{}>'.format(inc)) + lines.append('') + includes = h.get('include',[]) + if includes: + for inc in includes: + lines.append('#include "{}"'.format(inc)) + lines.append('') + if 'c++' in h: + lines.extend( ['#ifdef __cplusplus', 'extern "C" {', '#endif', ''] ) + postamble[0:0] = ['', '#ifdef __cplusplus', '}', '#endif'] + + if db: + apis = self.sorted_prototypes(header) + else: + apis = self.sequenced_prototypes(header) + if doxy and not db: + lines += [api.annotated for api in apis] + else: + lines += [api.prototype for api in apis] + lines.extend(postamble) + + return '\n'.join(lines) + '\n' + + def output_prototypes(self, outdir, format): + # Output the prototypes as C header files into the path at `outdir` + # * for 'api-ref' include annotaton, and use source sequencing + # * for 'api-db' strip annotations, and use identifier order + db = (format == 'api-db') + os.makedirs(outdir, exist_ok=True) + clean_dir(outdir) + for h in self.data['prototypes'].keys(): + fn = os.path.join(outdir, h + '.h') + os.makedirs(os.path.dirname(fn), exist_ok=True) + sig_file = open(fn, 'w', encoding='utf-8') + sig_file.write(self.prototype_header(h, notice=True, doxy=True, db=db)) + + + def resolve_any_xref(self, env, fromdocname, builder, target, + node, contnode): + # Check if this is a citation reference + m = re.match(r'\[([a-zA-Z0-9][-a-zA-Z0-9_. ]+)\]',target) + if m: + refnode = self.resolve_citeref(env, fromdocname, builder, 'cite', m.group(1), contnode) + if refnode: + return [('psa_c:cite', refnode)] + + m = re.match(r'(DM|AM|SG|T|M)\.[-a-zA-Z0-9+_.]+',target) + if m: + refnode = self.resolve_sraref(env, fromdocname, builder, target, contnode) + if refnode: + return [('psa_c:' + m.group(1).lower(), refnode)] + + # strip trailing parens, and check if an API item + refnode = self.resolve_apiref(env, fromdocname, builder, target, node, contnode) + if refnode: + return [('psa_c:ref', refnode)] + return [] + + # Weak reference: turn into a reference if the target is available, + # and keep as-is otherwise. + def resolve_xref(self, env, fromdocname, builder, + typ, target, node, contnode): + type = typ.split(':')[-1] + if type in ('cite', 'cite-title'): + return self.resolve_citeref(env, fromdocname, builder, type, target, contnode) + if type in ('term', 'scterm'): + return self.resolve_termref(env, fromdocname, builder, type, target, contnode) + if type == 'secref': + return self.resolve_secref(env, fromdocname, builder, type, target, node, contnode) + if type in ('numref', '*'): + return self.resolve_numref(env, fromdocname, builder, type, target, node, contnode) + if type in ('am', 'dm', 'sg', 't', 'm'): + return self.resolve_sraref(env, fromdocname, builder, + canonical_sra_id(type, target), contnode) + + return self.resolve_apiref(env, fromdocname, builder, target, node, contnode) + + # Try and resolve an API reference + def resolve_apiref(self, env, fromdocname, builder, + target, node, contnode): + # strip trailing parens + target = target.rstrip('()') + if target not in self.data['elements']: + return None + obj = self.data['elements'][target] + return make_refnode(builder, fromdocname, obj[0], make_c_target(target), + contnode, target) + + def resolve_secref(self, env, fromdocname, builder, + typ, target, node, contnode): + # resolve a section reference - use title for link text + # and add a latex pageref + # use the standard resolver to do the label lookup + e = env.domains['std'].resolve_xref(env, fromdocname, builder, + 'ref', target.lower(), node, contnode) + if not e: + contnode['classes'] = ['issue','secref'] + else: + e[0]['classes'] = ['secref'] + if 'refuri' in e: + id = e['refuri'][1:].replace('#', ':') + else: + id = fromdocname + ':' + e['refid'] + e += latexpageref(id) + return e + + def resolve_numref(self, env, fromdocname, builder, + typ, target, node, contnode): + # resolve a number reference + e = env.domains['std'].resolve_xref(env, fromdocname, builder, + 'numref', target.lower(), node, contnode) + if not (e and isinstance(e, nodes.reference)): + contnode['classes'] = ['issue','numref'] + return e + + # number_reference nodes are stripped in the latex writer + # so need to return a composite node which includes the number_refernence + # followed by the latex page-ref node + e[0]['classes'] = ['numref'] + n = nodes.inline('') + n += e + if 'refuri' in e: + id = e['refuri'][1:].replace('#', ':') + else: + id = fromdocname + ':' + e['refid'] + n += latexpageref(id) + return n + + def resolve_citeref(self, env, fromdocname, builder, + typ, target, contnode): + # resolve a citation reference (with optional title inclusion) + target = canonical_rfc(target) + docname, id, title = ReferenceTable.resolve_ref(env, target.lower()) + if not docname: + # If the xref cannot resolve, Sphinx writes the contnode - so + # make it show up as an issue in the output + contnode['classes'].append('issue') + return None + contnode = nodes.inline('', nodes_text(contnode), classes = ['cite']) + refnode = make_refnode(builder, fromdocname, docname, id, contnode) + if typ == 'cite-title' and title: + n = nodes.inline(nodes_text(contnode)) + n += nodes.emphasis('', *title) + n += nodes.Text(' ') + n += refnode + return n + return refnode + + def resolve_termref(self, env, fromdocname, builder, + typ, target, contnode): + # resolve a term reference + docname, label = TermTable.resolve_ref(env, target.lower()) + contnode['classes'].append(typ) + if not docname: + # If the xref cannot resolve, Sphinx writes the contnode - so + # make it show up as an issue in the output + contnode['classes'].append('issue') + return None + return make_refnode(builder, fromdocname, docname, label, contnode) + + def resolve_sraref(self, env, fromdocname, builder, + target, contnode): + key = nodes.make_id(target) + docname, label = SRADefinition.resolve_ref(env, key) + if not docname: + # If the xref cannot resolve, make it show up as an issue in the output + contnode['classes'].extend(['issue']) + return None + + n = nodes.inline(nodes_text(contnode), label, classes=['sraref']) + return make_refnode(builder, fromdocname, docname, 'sra-' + key, n) + +class BuildAPI(sphinx.builders.Builder): + def get_outdated_docs(self): + return 'api' + + def prepare_writing(self, docnames): + return + + def get_target_uri(self, docname, typ = None): + return docname + + # The API prototype output is independent of the structure of the source + # documents. So no output is generated for each updated source doc, instead + # the entire prototype API is output during the `finish()` method. + def write_doc(self, docname, doctree): + return + + def finish(self): + self.env.domains['psa_c'].output_prototypes(self.app.outdir, self.name) + +class API_db(BuildAPI): + name = 'api-db' + +class API_ref(BuildAPI): + name = 'headers' + +def alpha_section(secnum): + if not secnum or len(secnum) == 0: + return secnum + + secnum = list(secnum) + return tuple([string.ascii_uppercase[secnum[0]-1]] + secnum[1:]) + +def rewrite_section_numbers(env): + # This relies on the callbacks running _after_ the built-in + # TocTreeCollector has run, rewriting the section numbers to + # use Alphabetic section numbers for chapters in the Appendix + + def _walk_toc(node, alpha_sec=False): + for subnode in node.children: + if isinstance(subnode, (nodes.bullet_list, nodes.list_item, addnodes.only)): + _walk_toc(subnode, alpha_sec) + elif isinstance(subnode, addnodes.compact_paragraph) and alpha_sec: + reference = cast(nodes.reference, subnode[0]) + reference['secnumber'] = alpha_section(reference['secnumber']) + elif isinstance(subnode, addnodes.toctree): + _walk_toctree(subnode) + + def _walk_toctree(toctreenode: addnodes.toctree, alpha_sec=False) -> None: + for (_, ref) in toctreenode['entries']: + if ref in env.tocs: + _walk_toc(env.tocs[ref], alpha_sec) + + if alpha_sec: + env.toc_secnumbers[ref] = {k: alpha_section(v) + for k, v in env.toc_secnumbers[ref].items()} + + for docname in env.numbered_toctrees: + doctree = env.get_doctree(docname) + for toctreenode in doctree.traverse(addnodes.toctree): + alpha_sec = toctreenode.get('alpha_numbers', False) + _walk_toctree(toctreenode, alpha_sec) + + return [] + +def assign_figure_numbers(env): + # Rassign a figure number to each figure under a numbered toctree. + # But using the alpha section labels for appendices + # Each doc either has alpha chapters or number chapters (maintoc vs appendix) + # For each alpha-docs, accumulate the minimum fig index per fig-section + # Then rewrite the fignumbers using an alpha chapter, and reducing the index as required. + + if env.config.numfig and env.config.numfig_secnum_depth > 0: + alphadocs = [] + figoffset = {} + for docname, secnums in env.toc_secnumbers.items(): + if type(secnums[""][0]) is not int and docname in env.toc_fignumbers: + # This document is in an alpha-sectioned chapter + alphadocs.append(docname) + for kind, fignums in env.toc_fignumbers[docname].items(): + offsets = figoffset.setdefault(kind,{}) + for fignum in fignums.values(): + offsets[fignum[:-1]] = min(offsets.get(fignum[:-1],999), fignum[-1] - 1) + for docname in alphadocs: + for kind, fignums in env.toc_fignumbers[docname].items(): + for id, fignum in fignums.items(): + figbase = fignum[:-1] + fignums[id] = alpha_section(figbase) + (fignum[-1] - figoffset[kind][figbase],) + + return [] + +def apply_alpha_sections(app, env): + return rewrite_section_numbers(env) + assign_figure_numbers(env) + +def note_dependency(app, doctree): + # Rebuild everything when this extension's code changes. + app.env.note_dependency(__file__) + +def process_doctree_resolved(app, doctree, docname): + process_banner_nodes(app, doctree, docname) + process_header_nodes(app, doctree, docname) + +def setup(app): + # This version of the extension depends on table support only added in v5.3 + app.require_sphinx('5.3') + + app.add_config_value('psa_api_c_header', 'prototypes', 'env') + app.add_config_value('psa_api_tool_path', '', 'env') + app.add_config_value('psa_api_template_path', '', 'env') + app.add_config_value('psa_api_license', 'missing', 'env') + app.add_config_value('psa_api_retval_order', [], 'env') + app.add_config_value('psa_api_header_doxygen', 0, 'env') + app.add_config_value('psa_api_front_sections', [], 'env') + # This should be triggered on 'config-inited', but that event doesn't + # exist before Sphinx 1.8. + app.add_node(banner) + app.add_node(header_node) + app.connect('doctree-read', note_dependency) + app.connect('doctree-resolved', process_doctree_resolved) + app.connect('env-get-updated', apply_alpha_sections, 600) + + app.add_domain(PSA_C_Domain) + app.add_domain(DescriptionDomain) + app.add_builder(API_db) + app.add_builder(API_ref) + FrontSection.add_directives(app) + + return { + 'version': '1.0', + 'env_version': 14, + 'parallel_read_safe': False, # Can only verify this on Linux, not supported on MacOS or Windows + 'parallel_write_safe': True, + } diff --git a/tools/puml/psa-dataflow.pumh b/tools/puml/psa-dataflow.pumh new file mode 100644 index 00000000..33c32c26 --- /dev/null +++ b/tools/puml/psa-dataflow.pumh @@ -0,0 +1,29 @@ +' SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +' SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +!define dfd_process storage +!define dfd_store database +!define dfd_agent rectangle +!procedure dfd_tb($type = "trust boundary", $label="") + skinparam rectangle { + backgroundColor<<$type>> #FFFFFF90 + borderColor<<$type>> darkred + borderstyle<<$type>> dashed + borderThickness<<$type>> 1 + fontColor<<$type>> black + } + !if ($label == "") + rectangle <<$type>> + !else + rectangle "$label" <<$type>> + !endif +!endprocedure +!procedure dfd_align($type = "i b") + skinparam rectangle { + backgroundColor<<$type>> none + borderColor<<$type>> none + borderThickness<<$type>> 1 + fontColor<<$type>> none + } + rectangle <<$type>> +!endprocedure diff --git a/tools/puml/psa-lifecycle.pumh b/tools/puml/psa-lifecycle.pumh new file mode 100644 index 00000000..fcc20ac8 --- /dev/null +++ b/tools/puml/psa-lifecycle.pumh @@ -0,0 +1,21 @@ +' SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +' SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +skinparam rectangle { + backgroundColor #PSAMidBlue + borderThickness 0 + fontColor white +} + +skinparam card { + backgroundColor #0091BD20 + borderThickness 0 + fontColor black +} + +!define lifecycle_phase card +!define lifecycle_state rectangle +!define stakeholder note +!define stakeholder_skip label " " + +left to right direction diff --git a/tools/puml/psa-spec.pumh b/tools/puml/psa-spec.pumh new file mode 100644 index 00000000..42e6298e --- /dev/null +++ b/tools/puml/psa-spec.pumh @@ -0,0 +1,191 @@ +' SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +' SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +hide footbox +hide empty description +skinparam { + style strictuml + + defaultFontName roboto + defaultFontSize 12 + defaultMonospacedFontName roboto mono + + ArrowColor Black + + BackgroundColor ffffff55 + + RoundCorner 8 +} + +!define PSAGreen 95D600 +!define PSAMidBlue 0091BD +!define PSADarkBlue 002B49 +!define PSAMidGray 7D868C +!define PSALightGray E5ECEB + +skinparam legend { + backgroundColor e8e8e8 + fontSize 12 +} + +skinparam sequenceLifeLine { + backgroundColor White + borderColor Gray + borderThickness 1 +} + +skinparam sequenceGroup { + bodyBackgroundColor #ffffff80 + borderColor Gray + borderThickness 1 + backgroundColor #f0f0f0 + headerFontStyle normal + fontSize 11 +} + +skinparam sequenceBox { + borderColor none + backgroundColor #e0e0e0c0 + borderThickness 1 +} + +skinparam note { + backgroundColor #e8e8e8 + borderColor PSAMidGray + borderThickness 1 +} + +skinparam participant { + backgroundColor White + borderColor Black + borderThickness 1 +} + +skinparam actor { + backgroundColor White + borderColor Black + borderThickness 1 +} + +skinparam boundary { + backgroundColor White + borderColor Black + borderThickness 1 +} + +skinparam control { + backgroundColor White + borderColor Black + borderThickness 1 +} + +skinparam database { + backgroundColor White + borderColor Black + borderThickness 1 +} + +skinparam entity{ + backgroundColor White + borderColor Black + borderThickness 1 +} + +skinparam collections { + backgroundColor White + borderColor Black + borderThickness 1 +} + +skinparam queue { + backgroundColor White + borderColor Black + borderThickness 1 +} + +skinparam storage { + backgroundColor White + borderColor Black + borderThickness 1 +} + +skinparam rectangle { + backgroundColor White + borderColor Black + borderThickness 1 +} + +skinparam interface { + backgroundColor White + borderColor Black + borderThickness 1 +} + +skinparam condition { + backgroundColor White + borderColor Black + borderThickness 1 +} + +skinparam state { + backgroundColor White + borderColor Black + borderThickness 1 +} + +skinparam usecase { + backgroundColor White + borderColor Black + borderThickness 1 +} + +skinparam cloud { + backgroundColor #White + borderColor PSAMidGray + borderThickness 1 +} + +skinparam component { + backgroundColor #White + borderColor Black + borderThickness 1 +} + +skinparam node { + backgroundColor #White + borderColor PSAMidGray + borderThickness 1 +} + +skinparam frame { + backgroundColor #White + borderColor PSAMidGray + borderThickness 1 +} + +skinparam folder { + backgroundColor #White + borderColor PSAMidGray + borderThickness 1 +} + +skinparam ConditionEndStyle hline + +skinparam partition { + borderThickness 0 + borderColor f0f0f0 + backgroundColor #f0f0f0 + fontSize 11 +} + +skinparam activity { + backgroundColor White + borderColor Black + borderThickness 1 +} + +skinparam card { + backgroundColor White + borderColor Black + borderThickness 1 +} diff --git a/tools/rewrite-html-for-jekyll.py b/tools/rewrite-html-for-jekyll.py new file mode 100644 index 00000000..3b2e7b27 --- /dev/null +++ b/tools/rewrite-html-for-jekyll.py @@ -0,0 +1,22 @@ +# SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +# SPDX-License-Identifier: Apache-2.0 + +import glob, re + +files = [] +for f in glob.glob('**/*.html', recursive=True): + files.append(f) + +url_property = r'meta property="og:url" content="{{ site.url }}[^"]*"\s*/>' +url_replace = r'meta property="og:url" content="{{ page.url | absolute_url }}" />\n<link rel="canonical" href="{{ page.url | absolute_url }}" />' + +url_re = re.compile(url_property) + +for file in files: + with open(file, encoding='utf-8') as f: + text = f.read() + if re.search(url_re, text): + text = "---\n---\n\n" +re.sub(url_re, url_replace, text) + print("{}: update for Jekyll processing".format(file)) + with open(file, "w", encoding='utf-8') as f: + f.write(text) diff --git a/tools/templates/psa-api-2022/Arm_logo_blue_RGB.pdf b/tools/templates/psa-api-2022/Arm_logo_blue_RGB.pdf new file mode 100644 index 00000000..15fb0b55 Binary files /dev/null and b/tools/templates/psa-api-2022/Arm_logo_blue_RGB.pdf differ diff --git a/tools/templates/psa-api-2022/Arm_logo_blue_RGB.pdf.license b/tools/templates/psa-api-2022/Arm_logo_blue_RGB.pdf.license new file mode 100644 index 00000000..8c3078e2 --- /dev/null +++ b/tools/templates/psa-api-2022/Arm_logo_blue_RGB.pdf.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license diff --git a/tools/templates/psa-api-2022/Arm_logo_blue_RGB.svg b/tools/templates/psa-api-2022/Arm_logo_blue_RGB.svg new file mode 100644 index 00000000..4cdf634c --- /dev/null +++ b/tools/templates/psa-api-2022/Arm_logo_blue_RGB.svg @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.1" + id="Layer_1" + x="0px" + y="0px" + viewBox="0 0 236.5 72.099998" + xml:space="preserve" + sodipodi:docname="Arm_logo_blue_RGB.svg" + width="236.5" + height="72.099998" + inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"><metadata + id="metadata11"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs + id="defs9" /><sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1022" + inkscape:window-height="690" + id="namedview7" + showgrid="false" + inkscape:zoom="1.3156566" + inkscape:cx="118" + inkscape:cy="36.1" + inkscape:window-x="0" + inkscape:window-y="1102" + inkscape:window-maximized="0" + inkscape:current-layer="Layer_1" /> +<style + type="text/css" + id="style2"> + .st0{fill:#0091BD;} +</style> +<path + class="st0" + d="M 53.4,1.9 H 69.3 V 70 H 53.4 V 62.9 C 46.4,71 37.9,72.1 33,72.1 12,72.1 0,54.6 0,35.9 0,13.7 15.2,0.1 33.2,0.1 c 5,0 13.8,1.3 20.2,9.7 z M 16.2,36.2 c 0,11.8 7.4,21.7 18.9,21.7 10,0 19.3,-7.3 19.3,-21.5 0,-14.9 -9.2,-22 -19.3,-22 -11.5,0 -18.9,9.7 -18.9,21.8 z M 88.1,1.9 H 104 V 8 c 1.8,-2.1 4.4,-4.4 6.6,-5.7 3.1,-1.8 6.1,-2.3 9.7,-2.3 3.9,0 8.1,0.6 12.5,3.2 l -6.5,14.4 c -3.6,-2.3 -6.5,-2.4 -8.1,-2.4 -3.4,0 -6.8,0.5 -9.9,3.7 -4.4,4.7 -4.4,11.2 -4.4,15.7 V 69.9 H 88 v -68 z m 54.9,0 h 15.9 v 6.3 c 5.3,-6.5 11.6,-8.1 16.8,-8.1 7.1,0 13.8,3.4 17.6,10 5.7,-8.1 14.2,-10 20.2,-10 8.3,0 15.5,3.9 19.4,10.7 1.3,2.3 3.6,7.3 3.6,17.2 V 70.1 H 220.6 V 32.6 c 0,-7.6 -0.8,-10.7 -1.5,-12.1 -1,-2.6 -3.4,-6 -9.1,-6 -3.9,0 -7.3,2.1 -9.4,5 -2.8,3.9 -3.1,9.7 -3.1,15.5 V 70.1 H 181.6 V 32.6 c 0,-7.6 -0.8,-10.7 -1.5,-12.1 -1,-2.6 -3.4,-6 -9.1,-6 -3.9,0 -7.3,2.1 -9.4,5 -2.8,3.9 -3.1,9.7 -3.1,15.5 V 70.1 H 143 Z" + id="path4" /> +</svg> diff --git a/tools/templates/psa-api-2022/Arm_logo_blue_RGB.svg.license b/tools/templates/psa-api-2022/Arm_logo_blue_RGB.svg.license new file mode 100644 index 00000000..8c3078e2 --- /dev/null +++ b/tools/templates/psa-api-2022/Arm_logo_blue_RGB.svg.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license diff --git a/tools/templates/psa-api-2022/about-chapter.rst b/tools/templates/psa-api-2022/about-chapter.rst new file mode 100644 index 00000000..e2592aa8 --- /dev/null +++ b/tools/templates/psa-api-2022/about-chapter.rst @@ -0,0 +1,133 @@ +.. SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +.. role:: anchor + +.. _about-this-document: + +=================== +About this document +=================== + +.. insert-section:: Release information + :section: release-info + :break-after: + + The change history table lists the changes that have been made to this document. + + .. release-table:: Document revision history + +.. only:: include_todo + + .. insert-section:: TODO items + :section: todos + :break-after: + :not-in-toc: + + The following items are marked up as TODO in the document source: + + .. todolist:: + +.. insert-section:: |docfulltitle| + :not-in-toc: + + Copyright © |doccopyright|. The copyright statement reflects the fact that some + draft issues of this document have been released, to a limited circulation. + +.. include-license:: + +.. _license: + +.. insert-section:: License + :section: license + :class: license + :break-after: + +.. insert-section:: References + :section: references + + This document refers to the following documents. + + .. reference-table:: Documents referenced by this document + + +.. insert-section:: Terms and abbreviations + :section: terms + + This document uses the following terms and abbreviations. + + .. term-table:: Terms and abbreviations + :sorted: + +.. insert-section:: Potential for change + :section: potential-for-change + + The contents of this specification are subject to change. + + In particular, the following may change: + + * Feature addition, modification, or removal + * Parameter addition, modification, or removal + * Numerical values, encodings, bit maps + +.. insert-section:: Conventions + :section: conventions + + .. insert-section:: Typographical conventions + + The typographical conventions are: + + *italic* + Introduces special terminology, and denotes citations. + + ``monospace`` + Used for assembler syntax descriptions, pseudocode, and source code examples. + + Also used in the main text for instruction mnemonics and for references to + other items appearing in assembler syntax descriptions, pseudocode, and + source code examples. + + :sc:`small capitals` + Used for some common terms such as :sc:`implementation defined`. + + Used for a few terms that have specific technical meanings, and are included + in the *Terms and abbreviations*. + + :issue:`Red text` + Indicates an open issue. + + :anchor:`Blue text` + Indicates a link. This can be + + * A cross-reference to another location within the document + * A URL, for example :url:`example.com` + + .. insert-section:: Numbers + + Numbers are normally written in decimal. Binary numbers are preceded by 0b, and + hexadecimal numbers by ``0x``. + + In both cases, the prefix and the associated value are written in a monospace + font, for example ``0xFFFF0000``. To improve readability, long numbers can be + written with an underscore separator between every four characters, for example + ``0xFFFF_0000_0000_0000``. Ignore any underscores when interpreting the value of + a number. + +.. insert-section:: Current status and anticipated changes + :section: current-status + +.. _feedback: + +.. insert-section:: Feedback + :section: feedback + + We welcome feedback on the PSA Certified API documentation. + + If you have comments on the content of this book, visit :url:`github.com/arm-software/psa-api/issues` to create a new issue at the PSA Certified API GitHub project. Give: + + * The title (|docfulltitle|). + * The number and issue (|docid| |docrelease|). + * The location in the document to which your comments apply. + * A concise explanation of your comments. + + We also welcome general suggestions for additions and improvements. diff --git a/tools/templates/psa-api-2022/html-static/custom.css b/tools/templates/psa-api-2022/html-static/custom.css new file mode 100644 index 00000000..9b3d5ac1 --- /dev/null +++ b/tools/templates/psa-api-2022/html-static/custom.css @@ -0,0 +1,451 @@ +/* SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited */ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* CSS overrides for the html output */ + +body { + font-family: Lato, sans-serif; + font-size: 15px; + color: #1F2123; +} + +div.document { + width: 965px; +} + +div.bodywrapper { + margin: 0 0 0 270px; +} + +div.body { + background-color: unset; + color: #1F2123; + padding: 0; +} + +div.sphinxsidebar { + width: 240px; + font-size: 12.5px; + margin-top: -30px; +} + +div.sphinxsidebarwrapper { + padding: 0; +} + +div.sphinxsidebarwrapper p.logo { + margin: 0; +} + +div.footer { + width: 965px; +} + +div.watermark { + position: fixed; + width: 660px; + height: 100%; + z-index: -999; + pointer-events: none; + } + +div.watermark p { + color: #EEE; + font-size: 160px; + pointer-events: none; + user-select: none; + margin: 0px; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%) rotate(-45deg); + } + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: Lato, sans-serif; + font-weight: bold; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + font-family: Lato, sans-serif; + font-size: 20px; +} + +div.body input, div.sphinxsidebar input { + font-family: Lato, sans-serif; + font-size: 15px; +} + +a { + color: #0091BD; + text-decoration: none; +} + +a.reference { + border-bottom: none; +} + +a.reference:hover { + color: #00617E; + border-bottom: 1px solid #00617E; + background: unset; +} + +tt, code { + font-family: Inconsolata, monospace; + font-size: 93%; + background-color: unset; + color: #101010; +} + +code.xref, a code { + font-weight: normal; + color: #0091BD; + background-color: unset; + border-bottom: unset; +} + +pre { + font-family: Inconsolata, monospace; + font-size: 93%; + color: #101010; + background: rgba(187,187,187,0.12); + padding: 5px; + margin: 10px -6px; + line-height: 1.3em; + border-style: solid; + border-width: 1px; + border-radius: 5px; + border-color: rgba(187,187,187,0.3); +} + +/* Fix the specific overrides in basic.css and alabaster.css for code blocks */ +div.highlight pre, dl pre, blockquote pre, li pre { + padding: 5px; + margin: 10px -6px; +} + +sub { + font-size: 70%; + vertical-align: -10%; + font-weight: bold; +} + +sup { + font-size: 70%; + vertical-align: 25%; + font-weight: bold; +} + +/* Default table formatting is like 'booktabs', 'standard' formatting can + can be specified explicitly. + */ + + table.docutils { + font-size: unset; + box-shadow: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + /*width: 100%;*/ + border: 0; + border-top: 1px solid #AAA; + border-bottom: 1px solid #AAA; + margin-bottom: 1em; +} + +table.docutils.align-left { + margin-left: 0; + margin-right: auto; +} + +table.docutils.align-right { + margin-left: auto; + margin-right: 0; +} + +table.docutils.standard { + border: 1px solid #AAA; +} + +table.docutils.borderless { + border: 0; +} + +table.docutils.borderless.titletable { + margin-top: 40px; + width: 70%; + margin-right: 0px; + margin-left: auto; +} + +table.docutils caption, div.figure p.caption, figcaption { + font-size: 90%; + text-align: right; + margin-right: -13px; /* move permalink into margin */ +} + +table.docutils caption span.caption-number, div.figure p.caption span.caption-number, figcaption span.caption-number { + font-weight: bold; + font-style: normal; +} + +table.docutils td, table.docutils th { + border: 0; + padding: 0.3em 0.5em 0.3em 0.5em; + text-align: left; + vertical-align: top; +} + +/* Add all rules for standard table formatting */ +table.docutils.standard td, table.docutils.standard th { + border: 1px solid #AAA; +} + +table.docutils td p, table.docutils th p { + margin-block-start: .3em; + margin-block-end: .3em; +} + +table.docutils th > p:first-child, table.docutils td > p:first-child { + margin-top: 0px; +} + +table.docutils th { + font-weight: bold; + font-size: 90%; +} + +/* rule below stub rows */ +table.docutils th.stub { + border-bottom: none; +} + +table.docutils.standard th.stub { + border-bottom: 1px solid #AAA; +} + +/* rule below header rows */ +table.docutils th.head { + border-bottom: 0; +} + +table.docutils tr:last-child > th.head { + border-bottom: 1px solid #AAA; +} + +table.docutils.borderless tr:last-child > th.head { + border-bottom: 0; +} + +table.docutils.standard th.head { + border-bottom: 1px solid #AAA; +} + +table.docutils.borderless th.head { + border-bottom: 0; +} + +figure { + margin-inline-start: 0px; + margin-inline-end: 0px; +} + +div.figure div.legend, figcaption div.legend { + font-size: 90%; /* adds to the figcaption scaling */ + text-align: center; +} + +div.figure p.caption, div.figure div.legend p, figcaption p, figcaption div.legend { + margin-block-start: 0.2em; + margin-block-end: 0.5em; +} + +div.admonition { + margin: 5px 15px; + padding: 5px 15px; + background-color: unset; + border: 0; + border-left: 6px solid #DDD; +} + +div.admonition p.admonition-title { + font-family: Lato, sans-serif; + font-weight: bold; + font-size: 90%; +} + +p.admonition-title:after { + content: ""; +} + +div.admonition p { + margin-top: 0; + margin-bottom: 5px; +} + +div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { + background-color: unset; +} + +div.highlight { + background-color: unset; +} + +div.admonition div.highlight pre { + background-color: unset; +} + +div.warning { + border-left: 6px solid #FBB; +} + +div.warning p.admonition-title { + color: darkred; +} + +div.banner { + border: 2px solid #CC0; + background-color: rgba(255,255,0,0.25); +} + +div.rationale { + border-left: 6px solid #BFB; + background-color: rgba(127,255,127,0.125); +} + +div.rationale p.admonition-title { + color: darkgreen; +} + +div.admonition-todo { + border-left: 6px solid #CC0; + background-color: rgba(255,255,0,0.25); +} + +div.admonition-todo p.admonition-title { + color: #660; +} + +.scterm, .sc { + font-variant: small-caps; + text-transform: lowercase; +} + +.license{ + font-size: 80%; +} + +div.license p.sectiontitle { + display: block; + margin-top: 24px; + font-weight: bold; + font-size: 144%; +} + +.anchor { + color: #0091BD; +} + +.issue { + color: red; +} + +.term { + font-style: italic; +} + +.secref { + font-style: italic; +} + +.sectiontitle { + display: block; + margin-top: 30px; + font-weight: bold; + font-size: 180%; +} + +.sralabel { + font-weight: bold; +} + +.sradef { + font-weight: bold; + font-size: 90%; +} + +.sraref { + font-size: 90%; +} + +img.titlelogo { + float: left; + margin-top: 0.7em; + margin-bottom: 8em; + margin-right: 5%; + width: 25%; +} + +img.logo { + display: block; + margin: 1em auto; + width: 40%; +} + +div.sphinxsidebar hr { + width: 100%; +} + +dl dd { + margin-left: 3em; + margin-top: 0.2em; + margin-bottom: 0.8em; +} + +dl p { + margin-block-start: 0.6em; + margin-block-end: 0.6em; +} + +div.apisubitem dt > :first-child { + margin-top: 0; +} + +div.apisubitem dt > :last-child { + margin-bottom: 0; +} + +div.threat dt { + float: left; + clear: left; + width: 22ex; +} + +div.threat dt > :first-child { + margin-top: 0; +} + +div.threat dd { + margin-left:22ex; + padding-left: 1ex; +} + +div.riskrow table.docutils.borderless { + width: 100%; + margin-top: 0; + margin-bottom: 0.6em; +} + +div.riskrow table.docutils td { + padding: 0; +} + +div.riskrow table.docutils td p { + margin: 0; +} diff --git a/tools/templates/psa-api-2022/psa-api-tool.sty b/tools/templates/psa-api-2022/psa-api-tool.sty new file mode 100644 index 00000000..0660fa6f --- /dev/null +++ b/tools/templates/psa-api-2022/psa-api-tool.sty @@ -0,0 +1,492 @@ +% SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +% SPDX-License-Identifier: Apache-2.0 + +% Hide the warning when multiple inkscape-generated PDF [image] files are +% rendered on the same page +\pdfsuppresswarningpagegroup=1 + +% Set the ToC depth to include sub-section headings +\setcounter{tocdepth}{2} + +% Set the PDF bookmark depth to include sub-sub-section headings (API elements) +% The final level is not in the TOC +\def\psabookmarkdepth{3} + +\usepackage{apptools} +\usepackage{titletoc} +\usepackage{enumitem} +\usepackage[depth=\psabookmarkdepth, numbered]{bookmark} +\usepackage{caption} +\usepackage{ifthen} +\usepackage{xstring} +\usepackage[section]{placeins} +\usepackage{scalefnt} + +% The Sphinx DUrole command fails when multiple classes are defined +% This version splits the roles, and creates a nested set of calls to +% the sphinx command, +\let\sphinxDUrole\DUrole +\renewcommand{\DUrole}[2]{% + \IfSubStr{\detokenize{#1}}{,}{% + \StrBefore[1]{\detokenize{#1}}{,}[\myhead]% + \StrBehind[1]{\detokenize{#1}}{,}[\mytail]% + \expandafter\sphinxDUrole\expandafter{\myhead}{\expandafter\DUrole\expandafter{\mytail}{#2}}% + }{\sphinxDUrole{#1}{#2}}% +} +\MakeRobust\DUrole + +% PSA document styling +\def\psah {\normalfont\fontsize{20pt}{24pt}\selectfont\bfseries} +\def\psahh {\normalfont\fontsize{16pt}{19.2pt}\selectfont\bfseries} +\def\psahhh {\normalfont\fontsize{14pt}{16.8pt}\selectfont\bfseries} +\def\psahhhh {\normalfont\fontsize{12pt}{14.4pt}\selectfont\bfseries} +\def\psabody {\normalfont\fontsize{11pt}{13.2pt}\selectfont} +\def\psalicense {\normalfont\fontsize{9pt}{10.8pt}\selectfont} +\def\psasubtext {\normalfont\fontsize{8pt}{9.6pt}\selectfont} +\def\psasc {\scalefont{0.75}} +\def\psacitation {\itshape} +\def\psasubtitle {\normalfont\fontsize{10pt}{12pt}\selectfont\bfseries} +\def\psacaption {\psasubtitle} +\def\psathead {\psasubtitle} +\def\psalegend {\normalfont\fontsize{9pt}{10.8pt}\selectfont} + +\definecolor{psaissue}{rgb}{1,0,0} + +% Set up PSA style spacing rules +\frenchspacing +% remove justification on main text +\raggedright +% the line leading already gives us 2pt (in LaTeX spacing model) +\setlength{\parskip}{6pt plus 2pt minus 1pt} + + +% Define the heading styles for level 1-4 +\ifdefined\docchapterbreak + \titleclass{\chapter}{top} +\else + \titleclass{\chapter}{straight} +\fi +\titleformat{\chapter} + {\psah} + {\IfAppendix{\appendixname\ \thechapter:}{\thechapter}} + {0.5em}{}{} +\titlespacing{\chapter}{0pt}{*6}{*1} + +\titleformat{\section} + {\psahh} + {\thesection} + {0.5em}{}{} +\titlespacing{\section}{0pt}{*4.5}{*1} + +\titleformat{\subsection} + {\psahhh} + {\thesubsection} + {0.5em}{}{} +\titlespacing{\subsection}{0pt}{*4}{*1} + +\titleformat{\subsubsection} + {\psahhhh} + {\thesubsubsection} + {0.5em}{}{} +\titlespacing{\subsubsection}{0pt}{*3}{*1} + +% Add a watermark if requested +\ifdefined\docwatermark + \usepackage{draftwatermark} + \SetWatermarkText{\docwatermark} + \SetWatermarkScale{1} + \SetWatermarkColor[gray]{0.8} +\fi + +% remove emphasis on cross references +\def\sphinxcrossref#1{#1} + +% define a macro to provide a hyperlinked page reference, if on another page +% this is used for Section, Figure and Table references +\newcounter{testpagecount} +\DeclareRobustCommand\ifrefthispage[3]{% + \refstepcounter{testpagecount}\label{tpc\thetestpagecount}% + \ifthenelse{\equal{\pageref{#1}}{\pageref{tpc\thetestpagecount}}}{#2}{#3}% +} + +\newcommand\psapageref[1]{\ifrefthispage{#1}{}{\hyperref[#1]{{} on page~\pageref{#1}}}} + +% Define the format for the index sub-headings +\def\sphinxstyleindexlettergroup #1{{\psahhhh#1}\nopagebreak\vspace{4pt}} + +% set the size of API element names in subsubsection titles +\def\sphinxstyleliteralintitle#1{\texttt{\Large{#1}}} + +\raggedright + +% define the specification rule color +\definecolor{psarulecolor}{gray}{0.75} +\def\psarulewidth{.8pt} + +% Layout and style for tables + +\arrayrulecolor{psarulecolor} +\heavyrulewidth=.8pt + +% Set the table header rows font style +\def\sphinxstyletheadfamily {\psathead} + +% Set the table continuation style +\def\sphinxtablecontinued{\psacaption} + +% Table row spacing +\renewcommand{\arraystretch}{1.4} + +% Table captions +\captionsetup[table]{position=top} +\captionsetup{% + margin={2cm,0cm}, justification=raggedleft, singlelinecheck=false, + font=small, labelfont=bf, labelsep=space +} + +% Formatting for table cells +% * default paragraph spacing is 0pt, use a smaller (non-zero) spacing +% * reduced item spacing +% * left aligned text +\def\psacellformat{% + \setlength\parskip{3pt plus 1pt minus 1pt}% + \setlist[1]{topsep=2pt, partopsep=0pt, itemsep=1pt, parsep=2pt minus 1pt}% + \raggedright\arraybackslash% + } + +% redefine sphinx column types to be left aligned, with adjusted spacing +\makeatletter +\newcolumntype{\X}[2]{>{\psacellformat}p{\dimexpr + (\linewidth-\spx@arrayrulewidth)*#1/#2-\tw@\tabcolsep-\spx@arrayrulewidth\relax}} +\newcolumntype{\Y}[1]{>{\psacellformat}p{\dimexpr + #1\dimexpr\linewidth-\spx@arrayrulewidth\relax-\tw@\tabcolsep-\spx@arrayrulewidth\relax}} +\newcolumntype{T}{>{\psacellformat}L}% +\makeatother + +% Figure legend formatting comes after caption and may contain arbitrary body elements +\renewenvironment{sphinxlegend}{\par\medskip\psalegend}{\par} + +% format Notes to have a wider left margin +\renewenvironment{sphinxnote}[1] + {\list{}{\leftmargin1cm}\item[]\begin{sphinxlightbox}\sphinxstrong{#1}\par }{\end{sphinxlightbox}\endlist} + +% format for banner box. Use the environment defined for attention admonitions +\makeatletter +\newenvironment{sphinxclassbanner} + {% set parameters of heavybox + \def\spx@noticetype {attention}% + \sphinxcolorlet{spx@notice@bordercolor}{sphinxattentionBorderColor}% + \sphinxcolorlet{spx@notice@bgcolor}{sphinxattentionBgColor}% + \spx@notice@border \dimexpr1pt\relax + \begin{sphinxheavybox} + } + {\end{sphinxheavybox}} +\makeatother + +% format for internal-only rationale boxes. Use the environment defined for error admonitions +\makeatletter +\newenvironment{sphinxclassrationale} + {% set parameters of heavybox + \def\spx@noticetype {error}% + \sphinxcolorlet{spx@notice@bordercolor}{sphinxerrorBorderColor}% + \sphinxcolorlet{spx@notice@bgcolor}{sphinxerrorBgColor}% + \spx@notice@border \dimexpr1pt\relax + \begin{sphinxheavybox} + } + {\end{sphinxheavybox}} +\makeatother + +% Set up the PSA specification header/footer +\usepackage{fancyhdr} + \pagestyle{fancy} + \fancyhf{} + \fancyfoot[L]{\footnotesize{\docid\\{}\docreleasefull}} + \fancyfoot[C]{\footnotesize{\textit{Copyright \textcopyright \doccopyright}}} + \fancyfoot[R]{\footnotesize{Page \thepage}} + \renewcommand{\headrulewidth}{0pt} + \renewcommand{\footrulewidth}{\psarulewidth} + \renewcommand{\footrule}{{\color{psarulecolor} \rule{\headwidth}{\footrulewidth} \vskip -\footrulewidth}} + +\fancypagestyle{normal}{} +\fancypagestyle{plain}{} + +% Prevent the change of page number style from resetting the page number itself +\newcounter{savepage} +\let\oldpagenumbering\pagenumbering +\renewcommand{\pagenumbering}[1]{\setcounter{savepage}{\value{page}} \oldpagenumbering{#1} \setcounter{page}{\value{savepage}}} + +% A frontmatter environment, which continues roman page numbers, +% does not number titles, but includes them in the TOC. +\newcommand{\psafrontmatter}[1]% + {\pagenumbering{roman}% + \setcounter{secnumdepth}{#1} + } + +\newcommand{\psamain}[1] + {\clearpage% + \pagenumbering{arabic}% + \setcounter{secnumdepth}{#1} + } + +\newcommand{\psaappendix}[1] + {\ifdefined\docappendixbreak \clearpage\fi% + \setcounter{secnumdepth}{#1} + \appendix% + } + +\setcounter{secnumdepth}{2} +\setcounter{tocdepth}{2} + +% The title page command +\newenvironment{psatitle}% +{ + \pagestyle{empty} + \begin{titlepage} + + \setlength{\parindent}{0pt} + \begingroup % for PDF information dictionary + \def\endgraf{ }\def\and{\& }% + \pdfstringdefDisableCommands{\def\\{, }}% overwrite hyperref setup + \hypersetup{pdfauthor={\docauthor}, pdftitle={\docfulltitle{} \docversion}}% + \endgroup + + \noindent\begin{minipage}[t]{5.2cm} + \vspace{0pt}% required to get top-alignment of image and text + \sphinxlogo + \end{minipage} + \hfill\begin{minipage}[t]{0.67\textwidth}\raggedleft% + \vspace{0pt}% required to get top-alignment of image and text + {\psah \doclatextitle{} \docversion\par} + \ifdefined\docowner \medskip\psahhh\docowner\par \fi + \end{minipage} + + \bigskip\bigskip\bigskip + + \begin{table}[hbt!] + \begin{tabular}{ll} + Document number: & \docid \\ + Release Quality: & \docquality \\ + Issue Number: & \docissue \\ + Date of Issue: & \docdate + \end{tabular} + \end{table} + + \medskip + + \begingroup\raggedleft + \scriptsize{Copyright \textcopyright \doccopyright}\\\par + \endgroup + + \bigskip\bigskip\bigskip\bigskip +} +{ + \end{titlepage} + \pagestyle{plain} + \sphinxtableofcontents + \pagestyle{normal} +} + +% emulate small-caps: +\newcommand{\DUrolesc}[1] + {{\psasc\uppercase{#1}}} + +% small caps for special term references +\newcommand{\DUrolescterm}[1] + {{\psasc\uppercase{#1}}} + +% Other glossary term references are emphasized +\newcommand{\DUroleterm}[1] + {{\sphinxstyleemphasis{#1}}} + +% Define issue role as red color +\newcommand{\DUroleissue}[1] + {\textcolor{psaissue}{#1}} + +% Emphasise section and title-text references +\newcommand{\DUrolesecref}[1] + {{\sphinxstyleemphasis{#1}}} + +% SRA definition style +\newcommand{\DUrolesradef}[1] + {{\scalefont{.9}\sphinxstylestrong{#1}}} + +% SRA reference style +\newcommand{\DUrolesraref}[1] + {{\scalefont{.9}#1}} + +% SRA threat card label style +\newcommand{\DUrolesralabel}[1] + {{\sphinxstylestrong{#1}}} + +% associate anchor role with the InnerlinkColor +\newcommand{\DUroleanchor}[1] + {\textcolor{InnerLinkColor}{#1}} + +% Provide sectiontitle role for frontmatter titles that are not in TOC +\newcommand{\DUrolesectiontitle}[1] + {{\psahh #1}} + +\newcommand{\DUroleversionmodified}[1] + {{\sphinxstyleemphasis{#1}}} + +% define class environment for the license text (much smaller font) +\newenvironment{sphinxclasslicense} + {\psalicense\setlist[enumerate,1]{label=\bfseries(\roman*)}% + \renewcommand{\DUrolesectiontitle}[1] + {{\psahhh ##1}}% + } + {} + +% If running in a high enough version of sphinx, also +% Divert use of the sphinxalltt environment to use Verbatim. This requires +% setting a default config for Verbatim, which does not work in some earlier +% versions of Sphinx. +% +% This ensures that all literal blocks are rendered using the Verbatim +% configuration below, whether or not sphinx runs the highlighting engine on +% the block. +\newcommand{\useverbatimfortt}{% + \let\sphinxalltt\sphinxVerbatim% + \let\endsphinxalltt\endsphinxVerbatim% + \fvset{commandchars=\\\{\}}% + } + +% Set up the style for the Table of Contents + +\renewcommand{\contentsname}{\psahh Contents} +\contentsmargin{1cm} +\titlecontents{chapter}[1cm] + {\addvspace{16pt}} + {\psahhh\contentslabel{1cm}} + {\psahhh} + {\titlerule[0pt]\contentspage} +\titlecontents{section}[2cm] + {\addvspace{8pt}} + {\psahhhh\contentslabel{2cm}} + {\psahhhh} + {\titlerule[0pt]\contentspage} +\titlecontents{subsection}[2cm] + {} + {\psabody\contentslabel{1.5cm}} + {\psabody} + {\titlerule[0pt]\contentspage} + +% and remove sphinx's ToC overrides +\let\sphinxtableofcontentshook\relax + + +% This is something of a hack to get consistent, and differentiated API element +% subtitles in the specification. Simple specs might have API elements at +% level 3 headings (subsections), and complex ones at level 4 (subsubsection). +% So using a section level for the subtitles will yield inconsistent results. +% +% psa-api-tool.py uses `rubric` nodes for these sections (so don't use rubric in +% API reference for other things?). Unfortunately, Sphinx does not copy +% docutils and emit a \rubric{} command, it just emits \subsubsection*{}. +% +% As that [starred] command is not used for other elements, we replaced the +% \subsubsection command to intercept these uses and divert them to \rubric{}. +% We can then define \rubric{} as we wish - A bold 10pt runin for the main +% document text, and the original \subsubsection*{} in the appendix. +% +% Older versions of Sphinx directly use \paragraph{} for rubric, so +% also intercept level 5 headings and treat as rubric +% +% Heading 5 is used for all api subtitles +\newcommand{\subtitlett}[1]{{\normalfont\ttfamily #1}} +\newcommand{\apisubtitle}[1]{{\let\sphinxstyleliteralintitle\subtitlett #1}} +\titleformat{\paragraph} + {\psasubtitle} + {} + {0.5em}{\apisubtitle}{} +\titlespacing{\paragraph}{0pt}{*2}{4pt} + +\makeatletter +\let\oldsubsubsection\subsubsection +\renewcommand{\subsubsection} + % Only intercept rubrics in the main section + {\@ifstar{\IfAppendix{\oldsubsubsection*}{\paragraph*}}{\oldsubsubsection}} +\makeatother + + +% Set up item lists, enumerations and definition lists +% PSA current styleguide is incompatible with AIG. Will keep AIG at present +% [nb/ PSA guide is inconsistent with PSA examples] + +% Define spacing for lists +\setlist[1]{topsep=4pt, partopsep=0pt, itemsep=3pt, parsep=3pt plus 1pt minus 1pt} +\setlist[2]{topsep=2pt, partopsep=0pt, itemsep=1pt, parsep=1pt} +\setlist[3]{topsep=2pt, partopsep=0pt, itemsep=1pt, parsep=1pt} + +% Do not use multicols environment for hlist directive, but keep the compactness +\renewenvironment{multicols}[1]{\begingroup}{\endgroup} + +% AIG styleguide uses arabic, alpha for level 1 and 2 +% New versions of sphinx ignore this and set the formatting based on the +% source text +\setlist[enumerate,1]{label=\arabic*.} +\setlist[enumerate,2]{label=\alph*.} +\setlist[enumerate,3]{label=\roman*.} + +% AIG styleguide uses bullet and em-dash for level 1 and 2 +\setlist[itemize,1]{label=$\bullet$} +\setlist[itemize,2]{label=---} +\setlist[itemize,3]{label=$\circ$} + +% Remove Sphinx hack for formatting multiple terms in definition list +% It forces the list formatting, and breaks the styling done with enumitem +\renewcommand\sphinxlineitem[2]{\item[#1]\leavevmode#2}% + +% Define standard definition list format +\def\termmargin {13ex} +\def\termindent {2ex} +\def\termspace {1ex} + +\setlist[description]{% + style=nextline,% + labelindent=\termindent, labelwidth=!, labelsep=\termspace,% + itemindent=0ex, leftmargin=\termmargin,% + font=\normalfont,% + topsep=3pt, partopsep=0pt, itemsep=2pt, parsep=3pt% +} + +% Define API subitem definition list format +% psa-api-tool.py wraps the subitem lists in a apisubitem environment - so +% we can define that environment to set the description format +\def\apiitemwidth {29ex} +\def\apiitemindent { 2ex} +\def\apiitemspace { 1ex} + +\newenvironment{sphinxclassapisubitem} + {\setlist[description]{% + style=nextline,% + labelindent=\apiitemindent, labelwidth=\apiitemwidth,% + labelsep=\apiitemspace, itemindent=0ex, leftmargin=!,% + font=\normalfont,% + topsep=3pt, partopsep=0pt, itemsep=2pt, parsep=3pt% + }} + {} + +% Define Threat card definition list format +\def\threatlabelwidth {22ex} +\def\threatlabelindent { 0ex} +\def\threatlabelspace { 1ex} + +\newenvironment{sphinxclassthreat} + {\setlist[description]{% + style=nextline,% + labelindent=\threatlabelindent, labelwidth=\threatlabelwidth,% + labelsep=\threatlabelspace, itemindent=0ex, leftmargin=!,% + font=\sphinxstylestrong,% + topsep=6pt plus 2pt minus 1pt, partopsep=0pt,% + itemsep=2pt, parsep=6pt plus 2pt minus 1pt% + }} + {} + +\newenvironment{sphinxclassriskrow} + {\renewcommand{\arraystretch}{1.2}% + \setlength\tabcolsep{0pt}% + \def\sphinxattableend{}% + \vskip\dimexpr-\parskip-\baselineskip\relax% + } + {} diff --git a/tools/templates/psa-api-2022/sphinx-templates/indextoc.html b/tools/templates/psa-api-2022/sphinx-templates/indextoc.html new file mode 100644 index 00000000..549e3123 --- /dev/null +++ b/tools/templates/psa-api-2022/sphinx-templates/indextoc.html @@ -0,0 +1,8 @@ +<!-- +SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +SPDX-License-Identifier: Apache-2.0 +--> + +<ul> +<li class="toctree-l1"><a class="reference internal" href="{{ pathto("psa_c-identifiers.html", 1) }}">Index of API elements</a></li> +</ul> diff --git a/tools/templates/psa-api-2022/sphinx-templates/toc.html b/tools/templates/psa-api-2022/sphinx-templates/toc.html new file mode 100644 index 00000000..d11a6126 --- /dev/null +++ b/tools/templates/psa-api-2022/sphinx-templates/toc.html @@ -0,0 +1,11 @@ +<!-- +SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +SPDX-License-Identifier: Apache-2.0 +--> + +<hr /> +<h3><a href="{{ pathto(master_doc) }}"><b>{{ dochtmltitle }}</b></a></h3> +{{ docid }}<br/> +Version {{ docreleasefull }} +<hr /> +{{ toctree() }} diff --git a/tools/templates/psa-api-2022/template-conf.py b/tools/templates/psa-api-2022/template-conf.py new file mode 100644 index 00000000..8c6b80cd --- /dev/null +++ b/tools/templates/psa-api-2022/template-conf.py @@ -0,0 +1,97 @@ +# SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +# SPDX-License-Identifier: Apache-2.0 + +# -*- coding: utf-8 -*- +# +# Adjust or reset the template_info dictionary with customized +# sphinx configurations for this template + +template_info['logo_file'] = 'Arm_logo_blue_RGB' +template_info['html_theme'] = 'alabaster' +template_info['html_css_files'] = [ + ('https://fonts.googleapis.com', { 'rel': 'preconnect' }), + ('https://fonts.gstatic.com', { 'rel': 'preconnect', 'crossorigin': None }), + ('https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,400;0,700;1,400&display=swap', { 'rel': 'stylesheet' }), + ('https://fonts.googleapis.com/css2?family=Inconsolata:wght400;700&display=swap', { 'rel': 'stylesheet' }) +] +template_info['mathjax3_config'] = { + 'chtml': { + 'mtextInheritFont': True + } +} +template_info['latex_pointsize'] = '11pt' +template_info['latex_fonts'] = [ + r'\usepackage[default]{lato}', + r'\usepackage[scaled=0.91]{inconsolata}' + ] +template_info['latex_sphinxsetup'] = [ + # Use black for titles + 'TitleColor={rgb}{0,0,0}', + # Reduce margins + 'hmargin={1.9cm,1.25cm}', + 'vmargin={3.5cm, 3cm}', + 'marginpar=1.27cm', + # Format the verbatim blocks + 'verbatimwithframe=true', + 'verbatimsep=3pt', + 'VerbatimBorderColor={rgb}{0.9,0.9,0.9}', + 'verbatimborder=0.5pt', + 'VerbatimColor={rgb}{0.97,0.97,0.97}', + # format hyperlink color + 'InnerLinkColor={rgb}{0,0.569,0.741}', + 'OuterLinkColor={rgb}{0,0.569,0.741}', + # format admonitions + 'noteBorderColor={rgb}{0.667,0.667,0.667}', + 'warningBorderColor={rgb}{.75,0.5,0.5}', + 'warningborder=2pt', + # Use attention admonition for the front page banner + 'attentionBorderColor={rgb}{.8,.8,0}', + 'attentionBgColor={rgb}{1,1,.7}', + 'attentionborder=1pt', + # Use error admonition for rationale boxes + 'errorBorderColor={rgb}{.5,.75,.5}', + 'errorBgColor={rgb}{.9,.95,.9}', + 'errorborder=1pt', + # Use the normal font for headings + 'HeaderFamily=\\normalfont\\bfseries', + ] +template_info['latex_table_style'] = ['booktabs','nocolorrows'] +template_info['graphviz_dot_args'] = [ + '-Gfontname=Lato', + '-Gfontsize=12', + '-Nfontname=Lato', + '-Nfontsize=12', + '-Efontname=Lato', + '-Efontsize=12' +] + +def make_doc_filename(info, id, title, version, status): + if all((k in info for k in ('doc_id','quality','issue_no'))): + return '-'.join([id.replace(' ',''), title, version]) + return None + +template_info['make_filename'] = make_doc_filename + +template_info['front_sections'] = [ + 'abstract', + 'release-info', + 'todos', + 'license', + 'references', + 'terms', + 'potential-for-change', + 'conventions', + 'pseudocode', + 'assembler', + 'current-status', + 'feedback', + 'inclusive-language', + ] + +if 'author' not in doc_info: + doc_info['author'] = 'Arm Limited' +doc_info.setdefault('feedback', 'visit :url:`github.com/arm-software/psa-api/issues`' + + ' to create a new issue at the PSA Certified API GitHub project') +# force use of Arm copyright notice and OSS license +doc_info['copyright'] = 'Arm Limited and/or its affiliates' +doc_info['license'] = 'arm-psa-certified-api-license' diff --git a/tools/templates/psa-api-2022/title-page.rst b/tools/templates/psa-api-2022/title-page.rst new file mode 100644 index 00000000..211eba49 --- /dev/null +++ b/tools/templates/psa-api-2022/title-page.rst @@ -0,0 +1,42 @@ +.. SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +.. only:: html + + .. template-image:: Arm_logo_blue_RGB.svg + :alt: Arm + :class: titlelogo + +========================== +|docrsttitle| |docversion| +========================== + +.. only:: html + + .. csv-table:: + :class: titletable borderless + + Document number:, |docid| + Release Quality:, |docquality| + Issue Number:, |docissue| + Date of Issue:, |docdate| + +.. raw:: latex + + \begin{psatitle} + +.. insert-banner:: + +.. insert-section:: Abstract + :section: abstract + :not-in-toc: + +.. raw:: latex + + \end{psatitle} + +.. only:: html + + .. insert-section:: Contents + :not-in-toc: + :keep-if-empty: diff --git a/tools/templates/psa-api-2025/ARM_LOGO-2025_INK_RGB.pdf b/tools/templates/psa-api-2025/ARM_LOGO-2025_INK_RGB.pdf new file mode 100644 index 00000000..4b9affc9 Binary files /dev/null and b/tools/templates/psa-api-2025/ARM_LOGO-2025_INK_RGB.pdf differ diff --git a/tools/templates/psa-api-2025/ARM_LOGO-2025_INK_RGB.pdf.license b/tools/templates/psa-api-2025/ARM_LOGO-2025_INK_RGB.pdf.license new file mode 100644 index 00000000..8c3078e2 --- /dev/null +++ b/tools/templates/psa-api-2025/ARM_LOGO-2025_INK_RGB.pdf.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license diff --git a/tools/templates/psa-api-2025/ARM_LOGO-2025_INK_RGB.svg b/tools/templates/psa-api-2025/ARM_LOGO-2025_INK_RGB.svg new file mode 100644 index 00000000..84df36bb --- /dev/null +++ b/tools/templates/psa-api-2025/ARM_LOGO-2025_INK_RGB.svg @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 28.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + width="4332.3px" height="1318.7px" viewBox="0 0 4332.3 1318.7" style="enable-background:new 0 0 4332.3 1318.7;" + xml:space="preserve"> +<style type="text/css"> + .st0{fill:#080225;} +</style> +<g> + <path class="st0" d="M977.9,31.9h290.4v1247.6H977.9v-130.4C850.5,1297.2,693.4,1318,604.5,1318C219.3,1318,0,998,0,654.2 + C0,248.2,278.5-0.7,607.5-0.7c91.9,0,251.9,23.7,370.4,177.8V31.9z M296.3,660.1c0,216.3,136.3,397.1,346.7,397.1 + c183.7,0,352.6-133.3,352.6-394.1c0-272.6-168.9-403-352.6-403C432.6,260.1,296.3,437.9,296.3,660.1z M1614.1,31.9h290.4v112.6 + c32.6-38.5,80-80,121.5-103.7c56.3-32.6,112.6-41.5,177.8-41.5c71.1,0,148.2,11.9,228.2,59.3l-118.5,263.7 + c-65.2-41.5-118.5-44.4-148.2-44.4c-62.2,0-124.5,8.9-180.8,68.2c-80,85.9-80,204.5-80,287.4v646h-290.4V31.9z M2619.5,31.9h290.4 + v115.6C3007.7,29,3123.3-0.7,3218.1-0.7c130.4,0,251.9,62.2,323,183.7C3644.8,34.9,3801.9-0.7,3911.5-0.7 + c151.1,0,284.5,71.1,355.6,195.6c23.7,41.5,65.2,133.3,65.2,314.1v770.5h-290.4V592c0-139.3-14.8-195.6-26.7-222.2 + c-17.8-47.4-62.2-109.6-165.9-109.6c-71.1,0-133.3,38.5-171.9,91.9c-50.4,71.1-56.3,177.8-56.3,284.5v643h-290.4V592 + c0-139.3-14.8-195.6-26.7-222.2c-17.8-47.4-62.2-109.6-166-109.6c-71.1,0-133.3,38.5-171.9,91.9c-50.4,71.1-56.3,177.8-56.3,284.5 + v643h-290.4V31.9z"/> +</g> +</svg> diff --git a/tools/templates/psa-api-2025/ARM_LOGO-2025_INK_RGB.svg.license b/tools/templates/psa-api-2025/ARM_LOGO-2025_INK_RGB.svg.license new file mode 100644 index 00000000..8c3078e2 --- /dev/null +++ b/tools/templates/psa-api-2025/ARM_LOGO-2025_INK_RGB.svg.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license diff --git a/tools/templates/psa-api-2025/about-chapter.rst b/tools/templates/psa-api-2025/about-chapter.rst new file mode 100644 index 00000000..3e09491a --- /dev/null +++ b/tools/templates/psa-api-2025/about-chapter.rst @@ -0,0 +1,147 @@ +.. SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +.. role:: anchor + +.. _about-this-document: + +=================== +About this document +=================== + +.. _release-info: + +.. insert-section:: Release information + :section: release-info + :break-after: + + The change history table lists the changes that have been made to this document. + + .. release-table:: Document revision history + +.. only:: include_todo + + .. insert-section:: TODO items + :section: todos + :break-after: + :not-in-toc: + + The following items are marked up as TODO in the document source: + + .. todolist:: + +.. insert-section:: |docfulltitle| + :not-in-toc: + + Copyright © |doccopyright|. The copyright statement reflects the fact that some + draft issues of this document have been released, to a limited circulation. + +.. include-license:: + +.. _license: + +.. insert-section:: License + :section: license + :class: license + :break-after: + +.. _references: + +.. insert-section:: References + :section: references + + This document refers to the following documents. + + .. reference-table:: Documents referenced by this document + +.. _terms: + +.. insert-section:: Terms and abbreviations + :section: terms + + This document uses the following terms and abbreviations. + + .. term-table:: Terms and abbreviations + :sorted: + +.. _potential-for-change: + +.. insert-section:: Potential for change + :section: potential-for-change + + The contents of this specification are stable for |API| version |APIversion|. + + The following may change in |APIversion|.x maintenance updates to this specification: + + * Defect fixes + * Clarifications + * Editorial improvements + + Functionality additions, or any changes that affect the compatibility of the interfaces defined in this specification will only be included in a new major or minor version of the specification. + + +.. _conventions: + +.. insert-section:: Conventions + :section: conventions + + .. insert-section:: Typographical conventions + + The typographical conventions are: + + *italic* + Introduces special terminology, and denotes citations. + + ``monospace`` + Used for assembler syntax descriptions, pseudocode, and source code examples. + + Also used in the main text for instruction mnemonics and for references to + other items appearing in assembler syntax descriptions, pseudocode, and + source code examples. + + :sc:`small capitals` + Used for some common terms such as :sc:`implementation defined`. + + Used for a few terms that have specific technical meanings, and are included + in the *Terms and abbreviations*. + + :issue:`Red text` + Indicates an open issue. + + :anchor:`Blue text` + Indicates a link. This can be + + * A cross-reference to another location within the document + * A URL, for example :url:`example.com` + + .. insert-section:: Numbers + + Numbers are normally written in decimal. Binary numbers are preceded by 0b, and + hexadecimal numbers by ``0x``. + + In both cases, the prefix and the associated value are written in a monospace + font, for example ``0xFFFF0000``. To improve readability, long numbers can be + written with an underscore separator between every four characters, for example + ``0xFFFF_0000_0000_0000``. Ignore any underscores when interpreting the value of + a number. + +.. _current-status: + +.. insert-section:: Current status and anticipated changes + :section: current-status + +.. _feedback: + +.. insert-section:: Feedback + :section: feedback + + We welcome feedback on the |docfulltitle|. + + If you have comments on the content of this specification, |docfeedback|. Give: + + * The title (|docfulltitle|). + * The number and issue (|docid| |docrelease|). + * The location in the document to which your comments apply. + * A concise explanation of your comments. + + We also welcome general suggestions for additions and improvements. diff --git a/tools/templates/psa-api-2025/html-static/custom.css b/tools/templates/psa-api-2025/html-static/custom.css new file mode 100644 index 00000000..73985f7f --- /dev/null +++ b/tools/templates/psa-api-2025/html-static/custom.css @@ -0,0 +1,520 @@ +/* SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited */ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* CSS overrides for the html output */ + +body { + font-family: Lato, sans-serif; + font-size: 15px; + font-weight: 300; + color: #080225; +} + +div.document { + width: 965px; +} + +div.bodywrapper { + margin: 0 0 0 270px; +} + +div.body { + background-color: unset; + color: #080225; + padding: 0; +} + +div.sphinxsidebar { + width: 240px; + font-size: 12.5px; + margin-top: -30px; +} + +div.sphinxsidebarwrapper { + padding: 0; +} + +div.sphinxsidebarwrapper p.logo { + margin: 0; +} + +div.footer { + width: 965px; +} + +div.watermark { + position: fixed; + width: 660px; + height: 100%; + z-index: -999; + pointer-events: none; + } + +div.watermark p { + color: #EEE; + font-size: 160px; + font-weight: 400; + pointer-events: none; + user-select: none; + margin: 0px; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%) rotate(-45deg); + } + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: Lato, sans-serif; + font-weight: 400; +} + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + font-family: Lato, sans-serif; + font-size: 20px; +} + +p.rubric { + font-weight: 400; +} + +div.body input, div.sphinxsidebar input { + font-family: Lato, sans-serif; + font-size: 15px; +} + +div.line { + line-height: 1.4em; +} + +a, a:visited { + color: #0042c0; + text-decoration: none; +} + +a.reference, div.sphinxsidebar a.reference { + border-bottom: none; +} + +a.reference:hover, div.sphinxsidebar a.reference:hover, a:hover code, a:hover tt { + color: #561bc6; + border-bottom: 1px dotted #561bc6; + background: unset; +} + +pre a:hover, a:hover code, a:hover tt { + font-weight: 400; +} + +mjx-math { + color: #5b566d +} + +tt, code { + font-family: "Noto Sans Mono", monospace; + font-size: 80%; + background-color: unset; + color: #080225; +} + +h3 code, h4 code { + font-size: 88%; +} + +code.xref, a code { + font-weight: 300; + color: #0042c0; + background-color: unset; + border-bottom: unset; +} + +pre { + font-family: "Noto Sans Mono", monospace; + font-size: 76%; + color: #080225; + background: rgba(187,187,187,0.12); + padding: 5px; + margin: 10px -6px; + line-height: 1.3em; + border-style: solid; + border-width: 1px; + border-radius: 5px; + border-color: rgba(187,187,187,0.3); +} + +/* Fix the specific overrides in basic.css and alabaster.css for code blocks */ +div.highlight pre, dl pre, blockquote pre, li pre { + padding: 5px; + margin: 10px -6px; +} + +sub { + font-size: 70%; + vertical-align: -10%; + font-weight: 400; + color: #5b566d; +} + +sup { + font-size: 70%; + line-height: normal; + vertical-align: 25%; + font-weight: 400; + color: #5b566d; +} + +/* Default table formatting is like 'booktabs', 'standard' formatting can + can be specified explicitly. + */ + +table { + font-weight: 300; +} + +table.docutils { + font-size: unset; + box-shadow: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + /*width: 100%;*/ + border: 0; + border-top: 1px solid #AAA; + border-bottom: 1px solid #AAA; + margin-bottom: 1em; +} + +table.docutils.align-left { + margin-left: 0; + margin-right: auto; +} + +table.docutils.align-right { + margin-left: auto; + margin-right: 0; +} + +table.docutils.standard { + border: 1px solid #AAA; +} + +table.docutils.borderless { + border: 0; +} + +table.docutils.borderless.titletable { + margin-top: 40px; + width: 70%; + margin-right: 0px; + margin-left: auto; +} + +table.docutils caption, div.figure p.caption, figcaption { + font-size: 90%; + text-align: right; + margin-right: -13px; /* move permalink into margin */ +} + +table.docutils caption span.caption-number, div.figure p.caption span.caption-number, figcaption span.caption-number { + font-weight: 400; + font-style: normal; +} + +table.docutils td, table.docutils th { + border: 0; + padding: 0.15em 0.5em 0.15em 0.5em; + text-align: left; + vertical-align: baseline; +} + +table.docutils tr:first-child th, table.docutils tr:first-child td { + padding-top: 0.4em; +} + +/* Add all rules for standard table formatting */ +table.docutils.standard td, table.docutils.standard th { + border: 1px solid #AAA; +} + +table.docutils td p, table.docutils th p, table.docutils td .line-block { + margin-block-start: .3em; + margin-block-end: .3em; +} + +table.docutils th > p:first-child, table.docutils td > p:first-child { + margin-top: 0px; +} + +table.docutils th { + font-weight: 400; + font-size: 90%; +} + +/* rule below stub rows */ +table.docutils th.stub { + border-bottom: none; +} + +table.docutils.standard th.stub { + border-bottom: 1px solid #AAA; +} + +/* rule below header rows */ +table.docutils th.head { + border-bottom: 0; +} + +table.docutils tr:last-child > th.head { + border-bottom: 1px solid #AAA; +} + +table.docutils.borderless tr:last-child > th.head { + border-bottom: 0; +} + +table.docutils.standard th.head { + border-bottom: 1px solid #AAA; +} + +table.docutils.borderless th.head { + border-bottom: 0; +} + +figure { + margin-inline-start: 0px; + margin-inline-end: 0px; +} + +div.figure div.legend, figcaption div.legend { + font-size: 90%; /* adds to the figcaption scaling */ + text-align: center; +} + +div.figure p.caption, div.figure div.legend p, figcaption p, figcaption div.legend { + margin-block-start: 0.2em; + margin-block-end: 0.5em; +} + +table.docutils caption { + margin-bottom: 0.25em; +} + +div.admonition { + margin: 5px 15px; + padding: 5px 15px; + background-color: unset; + border: 0; + border-left: 6px solid #DDD; +} + +div.admonition p.admonition-title { + font-family: Lato, sans-serif; + font-weight: 400; + font-size: 90%; +} + +p.admonition-title:after { + content: ""; +} + +div.admonition p { + margin-top: 0; + margin-bottom: 5px; +} + +div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { + background-color: unset; +} + +div.highlight { + background-color: unset; +} + +div.admonition div.highlight pre { + background-color: unset; +} + +div.warning { + border-left: 6px solid #FBB; +} + +div.warning p.admonition-title { + color: darkred; +} + +div.banner { + border: 2px solid #CC0; + background-color: rgba(255,255,0,0.25); +} + +div.rationale { + border-left: 6px solid #BFB; + background-color: rgba(127,255,127,0.125); +} + +div.rationale p.admonition-title { + color: darkgreen; +} + +div.comment p.admonition-title { + color: #555; +} + +div.comment { + border-left: 6px solid #ccc; + background-color: #f8f8f8; + color: #555; + font-size: 95%; +} + +div.admonition-todo { + border-left: 6px solid #CC0; + background-color: rgba(255,255,0,0.25); +} + +div.admonition-todo p.admonition-title { + color: #660; +} + +.scterm, .sc { + font-variant: small-caps; + text-transform: lowercase; +} + +.license{ + font-size: 80%; +} + +div.license p.sectiontitle { + display: block; + margin-top: 24px; + font-weight: 400; + font-size: 144%; +} + +.anchor { + color: #0042c0; +} + +.issue { + color: red; +} + +.term { + font-style: italic; +} + +.secref { + font-style: italic; +} + +.sectiontitle { + display: block; + margin-top: 30px; + font-weight: 400; + font-size: 180%; +} + +.sralabel { + font-weight: 400; + font-size: 90%; +} + +.sradef { + font-weight: 400; + font-size: 90%; +} + +.sraref { + font-size: 90%; +} + +img.titlelogo { + float: left; + margin-top: 0.7em; + margin-bottom: 8em; + margin-right: 5%; + width: 25%; +} + +img.logo { + display: block; + margin: 1em auto; + width: 40%; +} + +div.sphinxsidebar hr { + width: 100%; +} + +dl dd { + margin-left: 3em; + margin-top: 0.2em; + margin-bottom: 0.8em; +} + +dl p { + margin-block-start: 0.6em; + margin-block-end: 0.6em; +} + +div.apisubitem dl { + display: grid; + grid-template-columns: 30ex 1fr; /* term column + description column */ + gap: 0 0.5ex; /* row gap, column gap */ + align-items: start; +} + +div.apisubitem dt p { + margin-block-start: 0; + margin-block-end: 0; +} + +div.apisubitem dd { + margin: 0; +} + +div.threat dl { + display: grid; + grid-template-columns: 20ex 1fr; /* term column + description column */ + gap: 0 0.5ex; /* row gap, column gap */ + align-items: start; +} + +div.threat dt p { + margin-block-start: 0; +} + +div.threat dd { + margin: 0; +} + +div.riskrow table.docutils.borderless { + width: 100%; + margin-top: 0; + margin-bottom: 0.6em; +} + +div.riskrow table.docutils td { + padding: 0; +} + +div.riskrow table.docutils td p { + margin: 0; +} + +ol { + list-style-type: decimal; /* 1, 2, 3 */ +} + +ol ol { + list-style-type: lower-alpha; /* a, b, c */ +} + +ol ol ol { + list-style-type: lower-roman; /* i, ii, iii */ +} diff --git a/tools/templates/psa-api-2025/psa-api-tool.sty b/tools/templates/psa-api-2025/psa-api-tool.sty new file mode 100644 index 00000000..a6516e2c --- /dev/null +++ b/tools/templates/psa-api-2025/psa-api-tool.sty @@ -0,0 +1,530 @@ +% SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +% SPDX-License-Identifier: Apache-2.0 + +% Hide the warning when multiple inkscape-generated PDF [image] files are +% rendered on the same page +\pdfsuppresswarningpagegroup=1 + +% Set the ToC depth to include sub-section headings +\setcounter{tocdepth}{2} + +% Set the PDF bookmark depth to include sub-sub-section headings (API elements) +% The final level is not in the TOC +\def\psabookmarkdepth{3} + +\usepackage{apptools} +\usepackage{titletoc} +\usepackage{enumitem} +\usepackage[depth=\psabookmarkdepth, numbered]{bookmark} +\usepackage{caption} +\usepackage{ifthen} +\usepackage{xstring} +\usepackage[section]{placeins} +\usepackage{scalefnt} + +% The Sphinx DUrole command fails when multiple classes are defined +% This version splits the roles, and creates a nested set of calls to +% the sphinx command, +\let\sphinxDUrole\DUrole +\renewcommand{\DUrole}[2]{% + \IfSubStr{\detokenize{#1}}{,}{% + \StrBefore[1]{\detokenize{#1}}{,}[\myhead]% + \StrBehind[1]{\detokenize{#1}}{,}[\mytail]% + \expandafter\sphinxDUrole\expandafter{\myhead}{\expandafter\DUrole\expandafter{\mytail}{#2}}% + }{\sphinxDUrole{#1}{#2}}% +} +\MakeRobust\DUrole + +% PSA document styling +\def\psah {\normalfont\fontsize{20pt}{24pt}\fontseries{m}\selectfont} +\def\psahh {\normalfont\fontsize{16pt}{19.2pt}\fontseries{m}\selectfont} +\def\psahhh {\normalfont\fontsize{14pt}{16.8pt}\fontseries{m}\selectfont} +\def\psahhhh {\normalfont\fontsize{12.5pt}{15pt}\fontseries{m}\selectfont} +\def\psabody {\normalfont\fontsize{11pt}{13.2pt}\fontseries{l}\selectfont} +\def\psasmall {\normalfont\fontsize{10pt}{12pt}\fontseries{l}\selectfont} +\def\psafootnote {\normalfont\fontsize{9pt}{10.8pt}\fontseries{l}\selectfont} +\def\psascript {\normalfont\fontsize{8pt}{9.6pt}\fontseries{l}\selectfont} +\def\psasc {\scalefont{0.75}} +\def\psacitation {\itshape} +\def\psalicense {\psafootnote} +\def\psasubtext {\psascript} +\def\psasubtitle {\psabody\mdseries} +\def\psathead {\psasmall\mdseries} +\def\psalabel {\psasmall\mdseries} +\def\psacaption {\psasmall} +\def\psalegend {\psafootnote} +\def\psacontd {\psafootnote\mdseries} + +\definecolor{psaissue}{rgb}{1,0,0} +\definecolor{psaink}{rgb}{0.03,0.01,0.145} + +% Set up PSA style spacing rules +\frenchspacing +% remove justification on main text +\raggedright +% the line leading already gives us 2pt (in LaTeX spacing model) +\setlength{\parskip}{6pt plus 2pt minus 1pt} + + +% Define the heading styles for level 1-4 +\ifdefined\docchapterbreak + \titleclass{\chapter}{top} +\else + \titleclass{\chapter}{straight} +\fi +\titleformat{\chapter} + {\psah} + {\IfAppendix{\appendixname\ \thechapter:}{\thechapter}} + {0.5em}{}{} +\titlespacing{\chapter}{0pt}{*6}{*1} + +\titleformat{\section} + {\psahh} + {\thesection} + {0.5em}{}{} +\titlespacing{\section}{0pt}{*4.5}{*1} + +\titleformat{\subsection} + {\psahhh} + {\thesubsection} + {0.5em}{}{} +\titlespacing{\subsection}{0pt}{*4}{*1} + +\titleformat{\subsubsection} + {\psahhhh} + {\thesubsubsection} + {0.5em}{}{} +\titlespacing{\subsubsection}{0pt}{*3}{*1} + +% Add a watermark if requested +\ifdefined\docwatermark + \usepackage{draftwatermark} + \SetWatermarkText{\mdseries\docwatermark} + \SetWatermarkScale{0.8} + \SetWatermarkColor[gray]{0.93} +\fi + +% remove emphasis on cross references +\def\sphinxcrossref#1{#1} + +% define a macro to provide a hyperlinked page reference, if on another page +% this is used for Section, Figure and Table references +\newcounter{testpagecount} +\DeclareRobustCommand\ifrefthispage[3]{% + \refstepcounter{testpagecount}\label{tpc\thetestpagecount}% + \ifthenelse{\equal{\pageref{#1}}{\pageref{tpc\thetestpagecount}}}{#2}{#3}% +} + +\newcommand\psapageref[1]{\ifrefthispage{#1}{}{\hyperref[#1]{{} on page~\pageref{#1}}}} + +% Define the format for the index sub-headings +\def\sphinxstyleindexlettergroup #1{{\psahhhh#1}\nopagebreak\vspace{4pt}} + +% set the size of API element names in subsubsection titles +\def\sphinxstyleliteralintitle#1{{\scalefont{1.1}\texttt{#1}}} + +\def\sphinxstylestrong#1{{\fontseries{m}\selectfont{#1}}} +\def\sphinxstrong#1{{\fontseries{m}\selectfont{#1}}} + +\raggedright + +% define the specification rule color +\definecolor{psarulecolor}{gray}{0.75} +\def\psarulewidth{.8pt} + +% Layout and style for tables + +\arrayrulecolor{psarulecolor} +\heavyrulewidth=.8pt + +% Set the table header rows font style +\def\sphinxstyletheadfamily {\psathead} + +% Set the table continuation style +\def\sphinxtablecontinued{\psacontd} + +% Table row spacing +\renewcommand{\arraystretch}{1.4} + +% Table captions +\captionsetup[table]{position=top} +\DeclareCaptionFormat{custom} +{% + \psalabel{#1#2}\psacaption{#3} +} +\captionsetup{% + format=custom, + margin={2cm,0cm}, justification=raggedleft, singlelinecheck=false, + labelsep=space +} + +% Formatting for table cells +% * default paragraph spacing is 0pt, use a smaller (non-zero) spacing +% * reduced item spacing +% * left aligned text +\def\psacellformat{% + \setlength\parskip{3pt plus 1pt minus 1pt}% + \setlist[1]{topsep=2pt, partopsep=0pt, itemsep=1pt, parsep=2pt minus 1pt}% + \raggedright\arraybackslash% + } + +% redefine sphinx column types to be left aligned, with adjusted spacing +\makeatletter +\newcolumntype{\X}[2]{>{\psacellformat}p{\dimexpr + (\linewidth-\spx@arrayrulewidth)*#1/#2-\tw@\tabcolsep-\spx@arrayrulewidth\relax}} +\newcolumntype{\Y}[1]{>{\psacellformat}p{\dimexpr + #1\dimexpr\linewidth-\spx@arrayrulewidth\relax-\tw@\tabcolsep-\spx@arrayrulewidth\relax}} +\newcolumntype{T}{>{\psacellformat}L}% +\makeatother + +% Figure legend formatting comes after caption and may contain arbitrary body elements +\renewenvironment{sphinxlegend}{\par\medskip\psalegend}{\par} + +% format Notes to have a wider left margin +\renewenvironment{sphinxnote}[1] + {\list{}{\leftmargin1cm}\item[]\begin{sphinxlightbox}\sphinxstrong{#1}\par }{\end{sphinxlightbox}\endlist} + +% format for banner box. Use the environment defined for attention admonitions +\makeatletter +\newenvironment{sphinxclassbanner} + {% set parameters of heavybox + \def\spx@noticetype {attention}% + \sphinxcolorlet{spx@notice@bordercolor}{sphinxattentionBorderColor}% + \sphinxcolorlet{spx@notice@bgcolor}{sphinxattentionBgColor}% + \spx@notice@border \dimexpr1pt\relax + \begin{sphinxheavybox} + } + {\end{sphinxheavybox}} +\makeatother + +% format for rationale boxes. Use the environment defined for error admonitions +\makeatletter +\newenvironment{sphinxclassrationale} + {% set parameters of heavybox + \def\spx@noticetype {error}% + \sphinxcolorlet{spx@notice@bordercolor}{sphinxerrorBorderColor}% + \sphinxcolorlet{spx@notice@bgcolor}{sphinxerrorBgColor}% + \spx@notice@border \dimexpr1pt\relax + \begin{sphinxheavybox} + } + {\end{sphinxheavybox}} +\makeatother + +% format for comment boxes. Use the environment defined for error admonitions +\makeatletter +\newenvironment{sphinxclasscomment} + {% set parameters of heavybox + \def\spx@noticetype {hint}% + \sphinxcolorlet{spx@notice@bordercolor}{sphinxhintBorderColor}% + \sphinxcolorlet{spx@notice@bgcolor}{sphinxhintBgColor}% + \spx@notice@border \dimexpr0pt\relax + \begin{sphinxheavybox}% + \color{sphinxhintTextColor}% + \psasmall + } + {\end{sphinxheavybox}} +\makeatother + +% Set up the PSA specification header/footer +\usepackage{fancyhdr} + \pagestyle{fancy} + \fancyhf{} + \fancyfoot[L]{\footnotesize\fontseries{l}\selectfont{\docid\\{}\docreleasefull}} + \fancyfoot[C]{\footnotesize\fontseries{l}\selectfont{\textit{Copyright \textcopyright \doccopyright}}} + \fancyfoot[R]{\footnotesize\fontseries{l}\selectfont{Page \thepage}} + \renewcommand{\headrulewidth}{0pt} + \renewcommand{\footrulewidth}{\psarulewidth} + \renewcommand{\footrule}{{\color{psarulecolor} \rule{\headwidth}{\footrulewidth} \vskip -\footrulewidth}} + +\fancypagestyle{normal}{} +\fancypagestyle{plain}{} + +% Prevent the change of page number style from resetting the page number itself +\newcounter{savepage} +\let\oldpagenumbering\pagenumbering +\renewcommand{\pagenumbering}[1]{\setcounter{savepage}{\value{page}} \oldpagenumbering{#1} \setcounter{page}{\value{savepage}}} + +% A frontmatter environment, which continues roman page numbers, +% does not number titles, but includes them in the TOC. +\newcommand{\psafrontmatter}[1]% + {\pagenumbering{roman}% + \setcounter{secnumdepth}{#1} + } + +\newcommand{\psamain}[1] + {\clearpage% + \pagenumbering{arabic}% + \setcounter{secnumdepth}{#1} + } + +\newcommand{\psaappendix}[1] + {\ifdefined\docappendixbreak \clearpage\fi% + \setcounter{secnumdepth}{#1} + \appendix% + } + +\setcounter{secnumdepth}{2} +\setcounter{tocdepth}{2} + +% The title page command +\newenvironment{psatitle}% +{ + \pagestyle{empty} + \begin{titlepage} + + \setlength{\parindent}{0pt} + \begingroup % for PDF information dictionary + \def\endgraf{ }\def\and{\& }% + \pdfstringdefDisableCommands{\def\\{, }}% overwrite hyperref setup + \hypersetup{pdfauthor={\docauthor}, pdftitle={\docfulltitle{} \docversion}}% + \endgroup + + \noindent\begin{minipage}[t]{5.2cm} + \vspace{0pt}% required to get top-alignment of image and text + \sphinxlogo + \end{minipage} + \hfill\begin{minipage}[t]{0.67\textwidth}\raggedleft% + \vspace{0pt}% required to get top-alignment of image and text + {\psah \doclatextitle{} \docversion\par} + \ifdefined\docowner \medskip\psahhh\docowner\par \fi + \end{minipage} + + \bigskip\bigskip\bigskip + + \newcommand{\psatitlecopyright}{ + \medskip + + \begingroup\raggedleft + \scriptsize{Copyright \textcopyright \doccopyright}\\\par + \endgroup + + \bigskip\bigskip\bigskip\bigskip + } +} +{ + \end{titlepage} + \pagestyle{plain} + \sphinxtableofcontents + \pagestyle{normal} +} + +% emulate small-caps: +\newcommand{\DUrolesc}[1] + {{\psasc\uppercase{#1}}} + +% small caps for special term references +\newcommand{\DUrolescterm}[1] + {{\psasc\uppercase{#1}}} + +% Other glossary term references are emphasized +\newcommand{\DUroleterm}[1] + {{\sphinxstyleemphasis{#1}}} + +% Define issue role as red color +\newcommand{\DUroleissue}[1] + {\textcolor{psaissue}{#1}} + +% Emphasise section and title-text references +\newcommand{\DUrolesecref}[1] + {{\sphinxstyleemphasis{#1}}} + +% SRA definition style +\newcommand{\DUrolesradef}[1] + {{\scalefont{.9}\sphinxstylestrong{#1}}} + +% SRA reference style +\newcommand{\DUrolesraref}[1] + {{\scalefont{.9}#1}} + +% SRA threat card label style +\newcommand{\DUrolesralabel}[1] + {{\psathead{#1}}} + +% associate anchor role with the InnerlinkColor +\newcommand{\DUroleanchor}[1] + {\textcolor{InnerLinkColor}{#1}} + +% Provide sectiontitle role for frontmatter titles that are not in TOC +\newcommand{\DUrolesectiontitle}[1] + {{\psahh #1}} + +\newcommand{\DUroleversionmodified}[1] + {{\psasmall\sphinxstyleemphasis{#1}}} + +% define class environment for the license text (much smaller font) +\newenvironment{sphinxclasslicense} + {\psalicense\setlist[enumerate,1]{label=\bfseries(\roman*)}% + \renewcommand{\DUrolesectiontitle}[1] + {{\psahhh ##1}}% + } + {} + +% If running in a high enough version of sphinx, also +% Divert use of the sphinxalltt environment to use Verbatim. This requires +% setting a default config for Verbatim, which does not work in some earlier +% versions of Sphinx. +% +% This ensures that all literal blocks are rendered using the Verbatim +% configuration below, whether or not sphinx runs the highlighting engine on +% the block. +\newcommand{\useverbatimfortt}{% + \let\sphinxalltt\sphinxVerbatim% + \let\endsphinxalltt\endsphinxVerbatim% + \fvset{commandchars=\\\{\}}% + } + +% Set up the style for the Table of Contents + +\renewcommand{\contentsname}{\psahh Contents} +\contentsmargin{1cm} +\titlecontents{chapter}[1cm] + {\addvspace{16pt}} + {\psahhh\contentslabel{1cm}} + {\psahhh} + {\titlerule[0pt]\contentspage} +\titlecontents{section}[2cm] + {\addvspace{8pt}} + {\psahhhh\contentslabel{2cm}} + {\psahhhh} + {\titlerule[0pt]\contentspage} +\titlecontents{subsection}[2cm] + {} + {\psabody\contentslabel{1.5cm}} + {\psabody} + {\titlerule[0pt]\contentspage} + +% and remove sphinx's ToC overrides +\let\sphinxtableofcontentshook\relax + +% Sphinx/pdflatex does not pick up the chpater title format from titlesec +% So hook the environment to insert formatting in the index title +\renewenvironment{sphinxtheindex}{% + \clearpage + \let\ixtitle\indexname% + \renewcommand{\indexname}{\psahh \ixtitle}% + \phantomsection % needed as no chapter, section, ... created + \begin{theindex}% + \addcontentsline{toc}{chapter}{\ixtitle}% + }{\end{theindex}} + +% This is something of a hack to get consistent, and differentiated API element +% subtitles in the specification. Simple specs might have API elements at +% level 3 headings (subsections), and complex ones at level 4 (subsubsection). +% So using a section level for the subtitles will yield inconsistent results. +% +% psa-api-tool.py uses `rubric` nodes for these sections (so don't use rubric in +% API reference for other things?). Unfortunately, Sphinx does not copy +% docutils and emit a \rubric{} command, it just emits \subsubsection*{}. +% +% As that [starred] command is not used for other elements, we replaced the +% \subsubsection command to intercept these uses and divert them to \rubric{}. +% We can then define \rubric{} as we wish - A bold 10pt runin for the main +% document text, and the original \subsubsection*{} in the appendix. +% +% Older versions of Sphinx directly use \paragraph{} for rubric, so +% also intercept level 5 headings and treat as rubric +% +% Heading 5 is used for all api subtitles +\newcommand{\subtitlett}[1]{{\normalfont\ttfamily #1}} +\newcommand{\apisubtitle}[1]{{\let\sphinxstyleliteralintitle\subtitlett #1}} +\titleformat{\paragraph} + {\psasubtitle} + {} + {0.5em}{\apisubtitle}{} +\titlespacing{\paragraph}{0pt}{*2}{4pt} + +\makeatletter +\let\oldsubsubsection\subsubsection +\renewcommand{\subsubsection} + % Only intercept rubrics in the main section + {\@ifstar{\IfAppendix{\oldsubsubsection*}{\paragraph*}}{\oldsubsubsection}} +\makeatother + +% Format lineblock text (consecutive lines prefixed with |) as a paragraph +% with forced line breaks +\renewenvironment{DUlineblock}[1]{% + \renewcommand{\item}[1][]{\par \renewcommand{\item}[1][]{\\}}% + \setlength{\leftmargin}{#1}% + \raggedright% +}{} + +% Set up item lists, enumerations and definition lists + +% Define spacing for lists +\setlist[1]{topsep=4pt, partopsep=0pt, itemsep=2pt, parsep=3pt plus 1pt minus 1pt} +\setlist[2]{topsep=2pt, partopsep=0pt, itemsep=1pt, parsep=1pt} +\setlist[3]{topsep=2pt, partopsep=0pt, itemsep=1pt, parsep=1pt} + +% Do not use multicols environment for hlist directive, but keep the compactness +\renewenvironment{multicols}[1]{\begingroup}{\endgroup} + +% Use arabic, alpha, roman for level 1-3 +% New versions of sphinx ignore this and set the formatting based on the +% source text +\setlist[enumerate,1]{label=\arabic*.} +\setlist[enumerate,2]{label=\alph*.} +\setlist[enumerate,3]{label=\roman*.} + +% Use bullet, em-dash, and circle for level 1-3 +\setlist[itemize,1]{label=$\bullet$} +\setlist[itemize,2]{label=---} +\setlist[itemize,3]{label=$\circ$} + +% Remove Sphinx hack for formatting multiple terms in definition list +% It forces the list formatting, and breaks the styling done with enumitem +\renewcommand\sphinxlineitem[2]{\item[#1]\leavevmode#2}% + +% Define standard definition list format +\def\termmargin {13ex} +\def\termindent {2ex} +\def\termspace {1ex} + +\setlist[description]{% + style=nextline,% + labelindent=\termindent, labelwidth=!, labelsep=\termspace,% + itemindent=0ex, leftmargin=\termmargin,% + font=\psabody,% + topsep=3pt, partopsep=0pt, itemsep=2pt, parsep=3pt% +} + +% Define API subitem definition list format +% This displays as a grid definition list, almost table-like +% psa-api-tool.py wraps the subitem lists in a apisubitem environment - so +% we can define that environment to set the description format +\def\apiitemwidth {31.5ex} +\def\apiitemindent { 0ex} +\def\apiitemspace {.5ex} + +\newenvironment{sphinxclassapisubitem} + {\setlist[description]{% + style=nextline,% + labelindent=\apiitemindent, labelwidth=\apiitemwidth,% + labelsep=\apiitemspace, itemindent=0ex, leftmargin=!,% + font=\psabody,% + topsep=3pt, partopsep=0pt, itemsep=2pt, parsep=3pt% + }} + {} + +% Define Threat card definition list format +\def\threatlabelwidth {20ex} +\def\threatlabelindent { 0ex} +\def\threatlabelspace {.5ex} + +\newenvironment{sphinxclassthreat} + {\setlist[description]{% + style=nextline,% + labelindent=\threatlabelindent, labelwidth=\threatlabelwidth,% + labelsep=\threatlabelspace, itemindent=0ex, leftmargin=!,% + font=\sphinxstylestrong,% + topsep=6pt plus 2pt minus 1pt, partopsep=0pt,% + itemsep=2pt, parsep=6pt plus 2pt minus 1pt% + }} + {} + +\newenvironment{sphinxclassriskrow} + {\renewcommand{\arraystretch}{1.2}% + \setlength\tabcolsep{0pt}% + \def\sphinxattableend{}% + \vskip\dimexpr-\parskip-\baselineskip\relax% + } + {} diff --git a/tools/templates/psa-api-2025/sphinx-templates/indextoc.html b/tools/templates/psa-api-2025/sphinx-templates/indextoc.html new file mode 100644 index 00000000..549e3123 --- /dev/null +++ b/tools/templates/psa-api-2025/sphinx-templates/indextoc.html @@ -0,0 +1,8 @@ +<!-- +SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +SPDX-License-Identifier: Apache-2.0 +--> + +<ul> +<li class="toctree-l1"><a class="reference internal" href="{{ pathto("psa_c-identifiers.html", 1) }}">Index of API elements</a></li> +</ul> diff --git a/tools/templates/psa-api-2025/sphinx-templates/toc.html b/tools/templates/psa-api-2025/sphinx-templates/toc.html new file mode 100644 index 00000000..878dd9d2 --- /dev/null +++ b/tools/templates/psa-api-2025/sphinx-templates/toc.html @@ -0,0 +1,11 @@ +<!-- +SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +SPDX-License-Identifier: Apache-2.0 +--> + +<hr /> +<h3><a href="{{ pathto(master_doc) }}">{{ dochtmltitle }}</a></h3> +{{ docid }}<br/> +Version {{ docreleasefull }} +<hr /> +{{ toctree() }} diff --git a/tools/templates/psa-api-2025/template-conf.py b/tools/templates/psa-api-2025/template-conf.py new file mode 100644 index 00000000..cb90d882 --- /dev/null +++ b/tools/templates/psa-api-2025/template-conf.py @@ -0,0 +1,106 @@ +# SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +# SPDX-License-Identifier: Apache-2.0 + +# -*- coding: utf-8 -*- +# +# Adjust or reset the template_info dictionary with customized +# sphinx configurations for this template + +template_info['logo_file'] = 'ARM_LOGO-2025_INK_RGB' +template_info['html_theme'] = 'alabaster' +template_info['html_css_files'] = [ + ('https://fonts.googleapis.com', { 'rel': 'preconnect' }), + ('https://fonts.gstatic.com', { 'rel': 'preconnect', 'crossorigin': None }), + ('https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,300;0,400;1,300;1,400&display=swap', { 'rel': 'stylesheet' }), + ('https://fonts.googleapis.com/css2?family=Noto+Sans+Mono:ital,wght@0,300;0,400;1,300&display=swap', { 'rel': 'stylesheet' }) +] +template_info['mathjax3_config'] = { + 'chtml': { + 'mtextInheritFont': False, + 'mtextFont': "Lato-Light", + } +} +template_info['latex_pointsize'] = '11pt' +template_info['latex_fonts']= [ + r'\usepackage[default]{lato}', + r'\usepackage[scale=.8]{noto-mono}' + ] +template_info['latex_sphinxsetup'] = [ + # Use black for titles + 'TitleColor={rgb}{0.03,0.01,0.145}', + # Reduce margins + 'hmargin={1.9cm,1.25cm}', + 'vmargin={3.5cm, 3cm}', + 'marginpar=1.27cm', + # Format the verbatim blocks + 'verbatimwithframe=true', + 'verbatimsep=3pt', + 'VerbatimBorderColor={rgb}{0.9,0.9,0.9}', + 'verbatimborder=0.5pt', + 'VerbatimColor={rgb}{0.97,0.97,0.97}', + # format hyperlink color + 'InnerLinkColor={rgb}{0,0.26,0.75}', + 'OuterLinkColor={rgb}{0,0.26,0.75}', + # format admonitions + 'noteBorderColor={rgb}{0.667,0.667,0.667}', + 'warningBorderColor={rgb}{.75,0.5,0.5}', + 'warningborder=2pt', + # Use attention admonition for the front page banner + 'attentionBorderColor={rgb}{.8,.8,0}', + 'attentionBgColor={rgb}{1,1,.7}', + 'attentionborder=1pt', + # Use error admonition for rationale boxes + 'errorBorderColor={rgb}{.5,.75,.5}', + 'errorBgColor={rgb}{.9,.95,.9}', + 'errorborder=1pt', + # Use hint admonition for comment boxes + 'hintBorderColor={rgb}{.6,.6,.6}', + 'hintBgColor={rgb}{.97,.97,.97}', + 'hintborder=0pt', + 'hintTextColor={rgb}{.4,.4,.4}', + # Use the normal font for headings + 'HeaderFamily=\\normalfont\\mdseries', +] +template_info['latex_table_style'] = ['booktabs','nocolorrows'] +template_info['graphviz_dot_args'] = [ + '-Gfontname=Lato', + '-Gfontsize=12', + '-Nfontname=Lato', + '-Nfontsize=12', + '-Efontname=Lato', + '-Efontsize=12' +] + +def make_doc_filename(info, id, title, version, status): + doc_parts = [id.replace(' ',''), title, version] + status = status.split(' ')[-1].lower() + if status != 'release': + doc_parts += [status] + if all((k in info for k in ('doc_id','quality','issue_no'))): + return '-'.join(doc_parts) + return None +template_info['make_filename'] = make_doc_filename + +template_info['front_sections'] = [ + 'abstract', + 'release-info', + 'todos', + 'license', + 'references', + 'terms', + 'potential-for-change', + 'conventions', + 'pseudocode', + 'assembler', + 'current-status', + 'feedback', + 'inclusive-language', + ] + +if 'author' not in doc_info: + doc_info['author'] = 'Arm Limited' +doc_info.setdefault('feedback', 'visit :url:`github.com/arm-software/psa-api/issues`' + + ' to create a new issue at the PSA Certified API GitHub project') +# force use of Arm copyright notice and OSS license +doc_info['copyright'] = 'Arm Limited and/or its affiliates' +doc_info['license'] = 'arm-psa-certified-api-license' diff --git a/tools/templates/psa-api-2025/title-page.rst b/tools/templates/psa-api-2025/title-page.rst new file mode 100644 index 00000000..297476ac --- /dev/null +++ b/tools/templates/psa-api-2025/title-page.rst @@ -0,0 +1,47 @@ +.. SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +.. only:: html + + .. template-image:: ARM_LOGO-2025_INK_RGB.svg + :alt: Arm + :class: titlelogo + +========================== +|docrsttitle| |docversion| +========================== + +.. raw:: latex + + \psabody\color{psaink} + + \begin{psatitle} + +.. csv-table:: + :class: titletable borderless + :align: left + + Document number:, |docid| + Release Quality:, |docquality| + Issue Number:, |docissue| + Date of Issue:, |docdate| + +.. raw:: latex + + \psatitlecopyright + +.. insert-banner:: + +.. insert-section:: Abstract + :section: abstract + :not-in-toc: + +.. raw:: latex + + \end{psatitle} + +.. only:: html + + .. insert-section:: Contents + :not-in-toc: + :keep-if-empty: diff --git a/tools/templates/psa-api-2026/about-chapter.rst b/tools/templates/psa-api-2026/about-chapter.rst new file mode 100644 index 00000000..a843725e --- /dev/null +++ b/tools/templates/psa-api-2026/about-chapter.rst @@ -0,0 +1,115 @@ +.. SPDX-FileCopyrightText: Copyright 2026 Arm Limited +.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +.. _introduction: + +Introduction +============ + +.. insert-section:: + :section: introduction + + .. todo:: Provide an introduction. + +.. insert-section:: + :section: api-status + +.. _feedback: + +.. insert-section:: + :section: feedback + + .. rubric:: Feedback + + We welcome feedback on the |docfulltitle|. + + If you have comments on the content of this specification, |docfeedback|. Give: + + * The title (|docfulltitle|). + * The number and issue (|docid| |docrelease|). + * The location in the document to which your comments apply. + * A concise explanation of your comments. + + We also welcome general suggestions for additions and improvements. + +.. _audience: + +.. insert-section:: Audience + :section: audience + :keep-if-empty: + + .. todo:: Describe the audience + +.. include-license:: + +.. _license: + +.. insert-section:: License + :section: license + :class: license + +.. _references: + +.. insert-section:: References + :section: references + + This section lists references applicable to this specification. The latest version of each reference applies unless a publication date or version is explicitly stated. + + .. reference-table:: Normative References + :layout: by-ref + :kind: normative + :sorted: + + .. reference-table:: Informative References + :layout: by-ref + :kind: informative + :sorted: + +.. _terms: + +.. insert-section:: Terminology and Definitions + :section: terms + + Selected terms used in this document are included in :numref:`tab-terms`. + + .. term-table:: Terminology and Definitions + :name: tab-terms + :sorted: + :kind: terms + +.. _abbreviations: + +.. insert-section:: Abbreviations + :section: abbreviations + + Abbreviations and notations used in this document are included in :numref:`tab-abbreviations`. + + .. term-table:: Abbreviations + :name: tab-abbreviations + :sorted: + :kind: abbreviations + +.. _release-info: + +.. insert-section:: Revision History + :section: release-info + + PSA Certified API documents use the following versioning scheme: + + * Those with version x.0 are major releases. + * Those versioned x.1, x.2, etc., are minor releases where changes typically introduce supplementary items that do not impact backward compatibility or interoperability of the specifications. + * Those versioned x.y.1, x.y.2, etc., are maintenance releases that incorporate errata and clarifications. + + :numref:`tab-revision-history` lists the changes that have been made to this document. + + .. release-table:: Revision History + :name: tab-revision-history + +.. only:: include_todo + + .. insert-section:: TODO items + :section: todos + + The following items are marked as TODO in the document source: + + .. todolist:: diff --git a/tools/templates/psa-api-2026/html-static/custom.css b/tools/templates/psa-api-2026/html-static/custom.css new file mode 100644 index 00000000..bca5234f --- /dev/null +++ b/tools/templates/psa-api-2026/html-static/custom.css @@ -0,0 +1,526 @@ +/* SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited */ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* CSS overrides for the html output */ + +body { + font-family: Roboto, sans-serif; + font-size: 15px; + font-weight: 300; + color: black; +} + +div.document { + width: 965px; +} + +div.bodywrapper { + margin: 0 0 0 270px; +} + +div.body { + background-color: unset; + color: black; + padding: 0; +} + +div.sphinxsidebar { + width: 240px; + font-size: 12.5px; + margin-top: -30px; +} + +div.sphinxsidebarwrapper { + padding: 0; +} + +div.sphinxsidebarwrapper p.logo { + margin: 0; +} + +div.footer { + width: 965px; +} + +div.watermark { + position: fixed; + width: 660px; + height: 100%; + z-index: -999; + pointer-events: none; + } + +div.watermark p { + color: #EEE; + font-size: 160px; + font-weight: 400; + pointer-events: none; + user-select: none; + margin: 0px; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%) rotate(-45deg); + } + +div.body h1, +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: Roboto, sans-serif; + font-weight: 400; + color: #002353; +} + +div.body h1 { font-size: 181%; } +div.body h2 { font-size: 145%; } +div.body h3 { font-size: 127%; } +div.body h4 { font-size: 114%; } +div.body h5 { font-size: 100%; } +div.body h6 { font-size: 100%; } + +div.sphinxsidebar h3, +div.sphinxsidebar h4 { + font-family: Roboto, sans-serif; + font-size: 20px; + font-weight: 400; + color: #002353; +} + +p.rubric { + font-weight: 400; + color: #002353; +} + +div.body input, div.sphinxsidebar input { + font-family: Roboto, sans-serif; + font-size: 15px; +} + +div.line { + line-height: 1.4em; +} + +a, a:visited { + color: #7D0097; + text-decoration: none; +} + +a.reference, div.sphinxsidebar a.reference { + border-bottom: none; +} + +a.reference:hover, div.sphinxsidebar a.reference:hover, a:hover code, a:hover tt { + color: #0688FF; + border-bottom: 1px dotted #0688FF; + background: unset; +} + +pre a:hover, a:hover code, a:hover tt { + font-weight: 400; +} + +mjx-math { + color: #555 +} + +tt, code { + font-family: "Roboto Mono", monospace; + font-size: 80%; + background-color: unset; + color: unset; +} + +h3 code, h4 code { + font-size: 88%; +} + +code.xref, a code { + font-weight: 300; + color: #7D0097; + background-color: unset; + border-bottom: unset; +} + +pre { + font-family: "Roboto Mono", monospace; + font-size: 80%; + color: black; + background: rgba(187,187,187,0.12); + padding: 5px; + margin: 10px -6px; + line-height: 1.3em; + border-style: solid; + border-width: 1px; + border-radius: 5px; + border-color: rgba(187,187,187,0.3); +} + +/* Fix the specific overrides in basic.css and alabaster.css for code blocks */ +div.highlight pre, dl pre, blockquote pre, li pre { + padding: 5px; + margin: 10px -6px; +} + +sub { + font-size: 70%; + vertical-align: -10%; + font-weight: 400; + color: #555; +} + +sup { + font-size: 70%; + line-height: normal; + vertical-align: 25%; + font-weight: 400; + color: #555; +} + +/* Default table formatting is like 'booktabs', 'standard' formatting can + can be specified explicitly. + */ + +table { + font-weight: 300; +} + +table.docutils { + font-size: unset; + box-shadow: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; + /*width: 100%;*/ + border: 0; + border-top: 1px solid #A1B4B4; + border-bottom: 1px solid #A1B4B4; + margin-bottom: 1em; +} + +table.docutils.align-left { + margin-left: 0; + margin-right: auto; +} + +table.docutils.align-right { + margin-left: auto; + margin-right: 0; +} + +table.docutils.standard { + border: 1px solid #A1B4B4; +} + +table.docutils.borderless { + border: 0; +} + +table.docutils.borderless.titletable { + margin-top: 40px; + width: 70%; + margin-right: 0px; + margin-left: auto; +} + +table.docutils caption, div.figure p.caption, figcaption { + font-size: 90%; + text-align: right; + margin-right: -13px; /* move permalink into margin */ +} + +table.docutils caption span.caption-number, div.figure p.caption span.caption-number, figcaption span.caption-number { + font-weight: 400; + font-style: normal; +} + +table.docutils td, table.docutils th { + border: 0; + padding: 0.15em 0.5em 0.15em 0.5em; + text-align: left; + vertical-align: baseline; +} + +table.docutils tr:first-child th, table.docutils tr:first-child td { + padding-top: 0.4em; +} + +/* Add all rules for standard table formatting */ +table.docutils.standard td, table.docutils.standard th { + border: 1px solid #AAA; +} + +table.docutils td p, table.docutils th p, table.docutils td .line-block { + margin-block-start: .3em; + margin-block-end: .3em; +} + +table.docutils th > p:first-child, table.docutils td > p:first-child { + margin-top: 0px; +} + +table.docutils th { + font-weight: 400; + font-size: 90%; +} + +/* rule below stub rows */ +table.docutils th.stub { + border-bottom: none; +} + +table.docutils.standard th.stub { + border-bottom: 1px solid #A1B4B4; +} + +/* rule below header rows */ +table.docutils th.head { + border-bottom: 0; +} + +table.docutils tr:last-child > th.head { + border-bottom: 1px solid #A1B4B4; +} + +table.docutils.borderless tr:last-child > th.head { + border-bottom: 0; +} + +table.docutils.standard th.head { + border-bottom: 1px solid #A1B4B4; +} + +table.docutils.borderless th.head { + border-bottom: 0; +} + +figure { + margin-inline-start: 0px; + margin-inline-end: 0px; +} + +div.figure div.legend, figcaption div.legend { + font-size: 90%; /* adds to the figcaption scaling */ + text-align: center; +} + +div.figure p.caption, div.figure div.legend p, figcaption p, figcaption div.legend { + margin-block-start: 0.2em; + margin-block-end: 0.5em; +} + +table.docutils caption { + margin-bottom: 0.25em; +} + +div.admonition { + margin: 5px 15px; + padding: 5px 15px; + background-color: unset; + border: 0; + border-left: 6px solid #DDD; +} + +div.admonition p.admonition-title { + font-family: Roboto, sans-serif; + font-weight: 400; + font-size: 90%; +} + +p.admonition-title:after { + content: ""; +} + +div.admonition p { + margin-top: 0; + margin-bottom: 5px; +} + +div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { + background-color: unset; +} + +div.highlight { + background-color: unset; +} + +div.admonition div.highlight pre { + background-color: unset; +} + +div.warning { + border-left: 6px solid #FBB; +} + +div.warning p.admonition-title { + color: darkred; +} + +div.banner { + border: 2px solid #CC0; + background-color: rgba(255,255,0,0.25); +} + +div.rationale { + border-left: 6px solid #BFB; + background-color: rgba(127,255,127,0.125); +} + +div.rationale p.admonition-title { + color: darkgreen; +} + +div.comment p.admonition-title { + color: #555; +} + +div.comment { + border-left: 6px solid #ccc; + background-color: #f8f8f8; + color: #555; + font-size: 95%; +} + +div.admonition-todo { + border-left: 6px solid #CC0; + background-color: rgba(255,255,0,0.25); +} + +div.admonition-todo p.admonition-title { + color: #660; +} + +.scterm, .sc { + font-variant: small-caps; + text-transform: lowercase; +} + +div.license span.sectiontitle { + margin-top: 24px; + font-size: 127%; +} + +.anchor { + color: #7D0097; +} + +.issue { + color: F04665; +} + +.term { + font-style: italic; +} + +.secref { + font-style: italic; +} + +.sectiontitle { + display: block; + margin-top: 30px; + font-weight: 400; + font-size: 145%; + color: #002353; +} + +.sralabel { + font-weight: 400; + font-size: 90%; +} + +.sradef { + font-weight: 400; + font-size: 90%; +} + +.sraref { + font-size: 90%; +} + +img.titlelogo { + float: left; + margin-top: 0.7em; + margin-bottom: 3em; + margin-right: 5%; + width: 25%; +} + +img.logo { + display: block; + margin: 1em auto; + width: 40%; +} + +div.sphinxsidebar hr { + width: 100%; +} + +dl dd { + margin-left: 3em; + margin-top: 0.2em; + margin-bottom: 0.8em; +} + +dl p { + margin-block-start: 0.6em; + margin-block-end: 0.6em; +} + +div.apisubitem dl { + display: grid; + grid-template-columns: 30ex 1fr; /* term column + description column */ + gap: 0 0.5ex; /* row gap, column gap */ + align-items: start; +} + +div.apisubitem dt p { + margin-block-start: 0; + margin-block-end: 0; +} + +div.apisubitem dd { + margin: 0; +} + +div.threat dl { + display: grid; + grid-template-columns: 20ex 1fr; /* term column + description column */ + gap: 0 0.5ex; /* row gap, column gap */ + align-items: start; +} + +div.threat dt p { + margin-block-start: 0; +} + +div.threat dd { + margin: 0; +} + +div.riskrow table.docutils.borderless { + width: 100%; + margin-top: 0; + margin-bottom: 0.6em; +} + +div.riskrow table.docutils td { + padding: 0; +} + +div.riskrow table.docutils td p { + margin: 0; +} + +ol { + list-style-type: decimal; /* 1, 2, 3 */ +} + +ol ol { + list-style-type: lower-alpha; /* a, b, c */ +} + +ol ol ol { + list-style-type: lower-roman; /* i, ii, iii */ +} diff --git a/tools/templates/psa-api-2026/logo.pdf b/tools/templates/psa-api-2026/logo.pdf new file mode 100644 index 00000000..a340e04a Binary files /dev/null and b/tools/templates/psa-api-2026/logo.pdf differ diff --git a/tools/templates/psa-api-2026/logo.pdf.license b/tools/templates/psa-api-2026/logo.pdf.license new file mode 100644 index 00000000..8c3078e2 --- /dev/null +++ b/tools/templates/psa-api-2026/logo.pdf.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license diff --git a/tools/templates/psa-api-2026/logo.svg b/tools/templates/psa-api-2026/logo.svg new file mode 100644 index 00000000..eecc6b11 --- /dev/null +++ b/tools/templates/psa-api-2026/logo.svg @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="40mm" + height="40mm" + viewBox="0 0 40 40" + version="1.1" + id="svg1" + inkscape:version="1.4.2 (ebf0e940, 2025-05-08)" + sodipodi:docname="logo.svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <sodipodi:namedview + id="namedview1" + pagecolor="#ffffff" + bordercolor="#000000" + borderopacity="0.25" + inkscape:showpageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" + inkscape:document-units="mm" + inkscape:zoom="3.82" + inkscape:cx="87.041885" + inkscape:cy="87.303665" + inkscape:window-width="1712" + inkscape:window-height="1186" + inkscape:window-x="0" + inkscape:window-y="30" + inkscape:window-maximized="0" + inkscape:current-layer="layer1" /> + <defs + id="defs1" /> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.2889px;line-height:1.2;font-family:Arial;-inkscape-font-specification:'Arial, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;text-decoration-color:#000000;writing-mode:lr-tb;direction:ltr;text-anchor:middle;fill:#b3b3b3;stroke:#b3b3b3;stroke-width:0.353;stroke-miterlimit:3;stroke-dasharray:none" + x="19.983463" + y="23.202988" + id="text1"><tspan + sodipodi:role="line" + id="tspan1" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.28890033px;font-family:Arial;-inkscape-font-specification:'Arial, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.353;stroke-dasharray:none;fill:#b3b3b3;stroke:#b3b3b3" + x="19.983463" + y="23.202988">[logo]</tspan></text> + </g> +</svg> diff --git a/tools/templates/psa-api-2026/logo.svg.license b/tools/templates/psa-api-2026/logo.svg.license new file mode 100644 index 00000000..8c3078e2 --- /dev/null +++ b/tools/templates/psa-api-2026/logo.svg.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license diff --git a/tools/templates/psa-api-2026/psa-api-tool.sty b/tools/templates/psa-api-2026/psa-api-tool.sty new file mode 100644 index 00000000..12e6fb87 --- /dev/null +++ b/tools/templates/psa-api-2026/psa-api-tool.sty @@ -0,0 +1,594 @@ +% SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +% SPDX-License-Identifier: Apache-2.0 + +% Hide the warning when multiple inkscape-generated PDF [image] files are +% rendered on the same page +\pdfsuppresswarningpagegroup=1 + +% Set the ToC depth to include sub-section headings +\setcounter{tocdepth}{2} + +% Set the PDF bookmark depth to include sub-sub-section headings (API elements) +% The final level is not in the TOC +\def\psabookmarkdepth{3} + +\usepackage{apptools} +\usepackage{titletoc} +\usepackage[titles]{tocloft} +\usepackage{enumitem} +\usepackage[depth=\psabookmarkdepth, numbered]{bookmark} +\usepackage{caption} +\usepackage{ifthen} +\usepackage{xstring} +\usepackage[section]{placeins} +\usepackage{scalefnt} +\usepackage{calc} +\usepackage{changepage} +\usepackage[figure,table]{totalcount} +\usepackage{zref-totpages} + +% The Sphinx DUrole command fails when multiple classes are defined +% This version splits the roles, and creates a nested set of calls to +% the sphinx command, +\let\sphinxDUrole\DUrole +\renewcommand{\DUrole}[2]{% + \IfSubStr{\detokenize{#1}}{,}{% + \StrBefore[1]{\detokenize{#1}}{,}[\myhead]% + \StrBehind[1]{\detokenize{#1}}{,}[\mytail]% + \expandafter\sphinxDUrole\expandafter{\myhead}{\expandafter\DUrole\expandafter{\mytail}{#2}}% + }{\sphinxDUrole{#1}{#2}}% +} +\MakeRobust\DUrole + +% PSA document styling +\def\psaht {\normalfont\fontsize{30pt}{36pt}\fontseries{m}\selectfont\color{gnavy}} +\def\psah {\normalfont\fontsize{20pt}{24pt}\fontseries{m}\selectfont\color{gnavy}} +\def\psahh {\normalfont\fontsize{16pt}{19.2pt}\fontseries{m}\selectfont\color{gnavy}} +\def\psahhh {\normalfont\fontsize{14pt}{16.8pt}\fontseries{m}\selectfont\color{gnavy}} +\def\psahhhh {\normalfont\fontsize{12.5pt}{15pt}\fontseries{m}\selectfont\color{gnavy}} +\def\psabody {\normalfont\fontsize{11pt}{13.2pt}\fontseries{l}\selectfont} +\def\psasmall {\normalfont\fontsize{10pt}{12pt}\fontseries{l}\selectfont} +\def\psafootnote {\normalfont\fontsize{9pt}{10.8pt}\fontseries{l}\selectfont} +\def\psascript {\normalfont\fontsize{8pt}{9.6pt}\fontseries{l}\selectfont} +\def\psasc {\scalefont{0.75}} +\def\psacitation {\itshape} +\def\psalicense {\psabody} +\def\psasubtext {\psascript} +\def\psasubtitle {\psabody\mdseries\color{gnavy}} +\def\psathead {\psasmall\mdseries} +\def\psalabel {\psasmall\mdseries} +\def\psacaption {\psasmall} +\def\psalegend {\psafootnote} +\def\psacontd {\psafootnote\mdseries} + +\definecolor{psaissue}{RGB}{240,70,101} +\definecolor{psaink}{rgb}{0.03,0.01,0.145} +\definecolor{gnavy}{rgb}{0,0.14,0.33} +\definecolor{gblue}{rgb}{0.02,0.53,1} +\definecolor{gplum}{rgb}{0.5,0,0.59} +\definecolor{ggrey}{rgb}{0.63,0.71,0.71} + +% Set up PSA style spacing rules +\frenchspacing +% remove justification on main text +\raggedright +% the line leading already gives us 2pt (in LaTeX spacing model) +\setlength{\parskip}{6pt plus 2pt minus 1pt} + + +% Define the heading styles for level 1-4 +\ifdefined\docchapterbreak + \titleclass{\chapter}{top} +\else + \titleclass{\chapter}{straight} +\fi +\titleformat{\chapter} + {\psah} + {\IfAppendix{Annex \thechapter:}{\thechapter}} + {0.5em}{}{} +\titlespacing{\chapter}{0pt}{*4}{*1} + +\titleformat{\section} + {\psahh} + {\thesection} + {0.5em}{}{} +\titlespacing{\section}{0pt}{*3}{*1} + +\titleformat{\subsection} + {\psahhh} + {\thesubsection} + {0.5em}{}{} +\titlespacing{\subsection}{0pt}{*3}{*1} + +\titleformat{\subsubsection} + {\psahhhh} + {\thesubsubsection} + {0.5em}{}{} +\titlespacing{\subsubsection}{0pt}{*3}{*1} + +% Add a watermark if requested +\ifdefined\docwatermark + \usepackage{draftwatermark} + \SetWatermarkText{\mdseries\docwatermark} + \SetWatermarkScale{0.8} + \SetWatermarkColor[gray]{0.93} +\fi + +% remove emphasis on cross references +\def\sphinxcrossref#1{#1} + +% define a macro to provide a hyperlinked page reference, if on another page +% this is used for Section, Figure and Table references +\newcounter{testpagecount} +\DeclareRobustCommand\ifrefthispage[3]{% + \refstepcounter{testpagecount}\label{tpc\thetestpagecount}% + \ifthenelse{\equal{\pageref{#1}}{\pageref{tpc\thetestpagecount}}}{#2}{#3}% +} + +\newcommand\psapageref[1]{\ifrefthispage{#1}{}{\hyperref[#1]{{} on page~\pageref{#1}}}} + +% Define the format for the index sub-headings +\def\sphinxstyleindexlettergroup #1{{\psahhhh#1}\nopagebreak\vspace{4pt}} + +% set the size of API element names in subsubsection titles +\def\sphinxstyleliteralintitle#1{{\scalefont{1.1}\texttt{#1}}} + +\def\sphinxstylestrong#1{{\fontseries{m}\selectfont{#1}}} +\def\sphinxstrong#1{{\fontseries{m}\selectfont{#1}}} + +\raggedright + +% define the specification rule color +\definecolor{psarulecolor}{rgb}{0.63,0.71,0.71} +\def\psarulewidth{.8pt} + +% Layout and style for tables + +\arrayrulecolor{psarulecolor} +\heavyrulewidth=.8pt + +% Set the table header rows font style +\def\sphinxstyletheadfamily {\psathead} + +% Set the table continuation style +\def\sphinxtablecontinued{\psacontd} + +% Table row spacing +\renewcommand{\arraystretch}{1.4} + +% Table captions +\captionsetup[table]{position=top} +\DeclareCaptionFormat{custom} +{% + \psalabel{#1#2}\psacaption{#3} +} +\captionsetup{% + format=custom, + margin={2cm,0cm}, justification=raggedleft, singlelinecheck=false, + labelsep=space +} + +% Formatting for table cells +% * default paragraph spacing is 0pt, use a smaller (non-zero) spacing +% * reduced item spacing +% * left aligned text +\def\psacellformat{% + \setlength\parskip{3pt plus 1pt minus 1pt}% + \setlist[1]{topsep=2pt, partopsep=0pt, itemsep=1pt, parsep=2pt minus 1pt}% + \raggedright\arraybackslash% + } + +% redefine sphinx column types to be left aligned, with adjusted spacing +\makeatletter +\newcolumntype{\X}[2]{>{\psacellformat}p{\dimexpr + (\linewidth-\spx@arrayrulewidth)*#1/#2-\tw@\tabcolsep-\spx@arrayrulewidth\relax}} +\newcolumntype{\Y}[1]{>{\psacellformat}p{\dimexpr + #1\dimexpr\linewidth-\spx@arrayrulewidth\relax-\tw@\tabcolsep-\spx@arrayrulewidth\relax}} +\newcolumntype{T}{>{\psacellformat}L}% +\makeatother + +% Figure legend formatting comes after caption and may contain arbitrary body elements +\renewenvironment{sphinxlegend}{\par\medskip\psalegend}{\par} + +% format Notes to have a wider left margin +\renewenvironment{sphinxnote}[1] + {\list{}{\leftmargin1cm}\item[]\begin{sphinxlightbox}\sphinxstrong{#1}\par }{\end{sphinxlightbox}\endlist} + +% format for banner box. Use the environment defined for attention admonitions +\makeatletter +\newenvironment{sphinxclassbanner} + {% set parameters of heavybox + \def\spx@noticetype {attention}% + \sphinxcolorlet{spx@notice@bordercolor}{sphinxattentionBorderColor}% + \sphinxcolorlet{spx@notice@bgcolor}{sphinxattentionBgColor}% + \spx@notice@border \dimexpr1pt\relax + \begin{sphinxheavybox} + } + {\end{sphinxheavybox}} +\makeatother + +% format for rationale boxes. Use the environment defined for error admonitions +\makeatletter +\newenvironment{sphinxclassrationale} + {% set parameters of heavybox + \def\spx@noticetype {error}% + \sphinxcolorlet{spx@notice@bordercolor}{sphinxerrorBorderColor}% + \sphinxcolorlet{spx@notice@bgcolor}{sphinxerrorBgColor}% + \spx@notice@border \dimexpr1pt\relax + \begin{sphinxheavybox} + } + {\end{sphinxheavybox}} +\makeatother + +% format for comment boxes. Use the environment defined for error admonitions +\makeatletter +\newenvironment{sphinxclasscomment} + {% set parameters of heavybox + \def\spx@noticetype {hint}% + \sphinxcolorlet{spx@notice@bordercolor}{sphinxhintBorderColor}% + \sphinxcolorlet{spx@notice@bgcolor}{sphinxhintBgColor}% + \spx@notice@border \dimexpr0pt\relax + \begin{sphinxheavybox}% + \color{sphinxhintTextColor}% + \psasmall + } + {\end{sphinxheavybox}} +\makeatother + +% Set up the PSA specification header/footer +\geometry{head=1cm,headsep=0.22cm,foot=1.73cm} +\usepackage{fancyhdr} + \pagestyle{fancy} + \fancyhf{} + \fancyhead[L]{\psasmall\docfulltitle} + \fancyhead[C]{\psasmall\docstatus} + \fancyhead[R]{\psasmall{}v\docrelease} + \renewcommand{\headrulewidth}{\psarulewidth} + \renewcommand{\headrule}{{\color{psarulecolor}\vskip -8pt\rule{\headwidth}{\headrulewidth}}} + \renewcommand{\footrulewidth}{\psarulewidth} + \renewcommand{\footrule}{{\color{psarulecolor} \rule{\headwidth}{\footrulewidth} \vskip -\footrulewidth}} + \fancyfoot[L]{\psasmall\textcolor{psaissue}{Unofficial publication}} + \fancyfoot[C]{\psascript\selectfont{\textit{Copyright \textcopyright \doccopyright}}} + \fancyfoot[R]{\psasmall{}Page \thepage} + +\fancypagestyle{normal}{} +\fancypagestyle{plain}{} + +% Prevent the change of page number style from resetting the page number itself +\newcounter{savepage} +\let\oldpagenumbering\pagenumbering +\renewcommand{\pagenumbering}[1]{\setcounter{savepage}{\value{page}} \oldpagenumbering{#1} \setcounter{page}{\value{savepage}}} + +% A frontmatter environment, which continues roman page numbers, +% does not number titles, but includes them in the TOC. +\newcommand{\psafrontmatter}[1]% + {\setcounter{secnumdepth}{#1}} + +\newcommand{\psamain}[2] + {\clearpage% + \setcounter{secnumdepth}{#1} + \renewcommand{\thetable}{#2\arabic{table}} + \renewcommand{\thefigure}{#2\arabic{figure}} + } + +\newcommand{\psaappendix}[2] + {\ifdefined\docappendixbreak \clearpage\fi% + \setcounter{secnumdepth}{#1} + \appendix% + \renewcommand{\thetable}{#2\arabic{table}} + \renewcommand{\thefigure}{#2\arabic{figure}} + } + +\setcounter{secnumdepth}{2} +\setcounter{tocdepth}{2} + +% Remove the page numbering changes from the default Sphinx manual document +\makeatletter +\renewcommand{\sphinxtableofcontents}{% + \begingroup + \parskip \z@skip + \sphinxtableofcontentshook + \tableofcontents + \endgroup + \if@openright\cleardoublepage\else\clearpage\fi +} +\makeatother + +% List of tables and figures +\newcommand{\psalistoftables}{ + \renewcommand{\listtablename}{Tables} + \cftsetindents{tab}{0cm}{2cm} + \renewcommand{\cfttabfont}{\psabody} + \renewcommand{\cfttabpresnum}{Table } + \renewcommand{\cfttabaftersnum}{:} + \renewcommand{\cfttabdotsep}{\cftnodots} + \renewcommand{\cfttabpagefont}{\psabody} + \listoftables +} +\newcommand{\psalistoffigures}{ + \renewcommand{\listfigurename}{Figures} + \cftsetindents{fig}{0cm}{2cm} + \renewcommand{\cftfigfont}{\psabody} + \renewcommand{\cftfigpresnum}{Figure } + \renewcommand{\cftfigaftersnum}{:} + \renewcommand{\cftfigdotsep}{\cftnodots} + \renewcommand{\cftfigpagefont}{\psabody} + \listoffigures +} + +% The title page command +\newenvironment{psatitle}% +{ + \thispagestyle{empty} + \setlength{\parindent}{0pt} + + % PDF information dictionary + \begingroup + \def\endgraf{ }\def\and{\& }% + \pdfstringdefDisableCommands{\def\\{, }}% overwrite hyperref setup + \hypersetup{% + pdfauthor={\docauthor},% + pdftitle={\docfulltitle},% + pdfsubject={\docrelease}% + }% + \endgroup + + % Placeholder logo + \noindent\begin{minipage}[t]{5.2cm} + \vspace{0pt}% required to get top-alignment of image and text + \sphinxlogo + \end{minipage} + \hfill\begin{minipage}[t]{0.67\textwidth}\raggedleft% + \vspace{0pt}% required to get top-alignment of image and text + {\psah \doclatextitle{} \par} + \end{minipage} + + \bigskip\bigskip\bigskip + + \newcommand{\psatitlecopyright}{ + \medskip + + \begingroup\raggedleft + \scriptsize{Copyright \textcopyright \doccopyright}\\\par + \endgroup + + \bigskip\bigskip\bigskip\bigskip + } + % Title page information table, copyright and banner will follow +} +{ + \clearpage + + % Contents tables + \pagestyle{plain} + \pagenumbering{arabic} + \begingroup + \sphinxtableofcontents + \iftotaltables\psalistoftables\fi + \let\clearpage\relax % prevent page break between tables + \iftotalfigures\psalistoffigures\fi + \endgroup + + \pagestyle{normal} +} + +% emulate small-caps: +\newcommand{\DUrolesc}[1] + {{\psasc\uppercase{#1}}} + +% small caps for special term references +\newcommand{\DUrolescterm}[1] + {{\psasc\uppercase{#1}}} + +% Other glossary term references are emphasized +\newcommand{\DUroleterm}[1] + {{\sphinxstyleemphasis{#1}}} + +% Define issue role as red color +\newcommand{\DUroleissue}[1] + {\textcolor{psaissue}{#1}} + +% Emphasise section and title-text references +\newcommand{\DUrolesecref}[1] + {{\sphinxstyleemphasis{#1}}} + +% SRA definition style +\newcommand{\DUrolesradef}[1] + {{\scalefont{.9}\sphinxstylestrong{#1}}} + +% SRA reference style +\newcommand{\DUrolesraref}[1] + {{\scalefont{.9}#1}} + +% SRA threat card label style +\newcommand{\DUrolesralabel}[1] + {{\psathead{#1}}} + +% associate anchor role with the InnerlinkColor +\newcommand{\DUroleanchor}[1] + {\textcolor{InnerLinkColor}{#1}} + +% Provide sectiontitle role for frontmatter titles that are not in TOC +\newcommand{\DUrolesectiontitle}[1] + {{\psahh #1}} + +\newcommand{\DUroleversionmodified}[1] + {{\psasmall\sphinxstyleemphasis{#1}}} + +% define class environment for the license text (much smaller font) +\newenvironment{sphinxclasslicense} + {\psalicense\setlist[enumerate,1]{label=\mdseries(\roman*)}% + \renewcommand{\DUrolesectiontitle}[1] + {{\psahhh ##1}}% + } + {} + +% If running in a high enough version of sphinx, also +% Divert use of the sphinxalltt environment to use Verbatim. This requires +% setting a default config for Verbatim, which does not work in some earlier +% versions of Sphinx. +% +% This ensures that all literal blocks are rendered using the Verbatim +% configuration below, whether or not sphinx runs the highlighting engine on +% the block. +\newcommand{\useverbatimfortt}{% + \let\sphinxalltt\sphinxVerbatim% + \let\endsphinxalltt\endsphinxVerbatim% + \fvset{commandchars=\\\{\}}% + } + +% Set up the style for the Table of Contents + +\renewcommand{\contentsname}{Contents} +\contentsmargin{1cm} +\titlecontents{chapter}[1cm] + {\addvspace{12pt}} + {\psahhh\contentslabel{1cm}} + {\psahhh} + {\titlerule[0pt]\contentspage} +\titlecontents{section}[2cm] + {\addvspace{2pt}} + {\psahhhh\contentslabel{2cm}} + {\psahhhh} + {\titlerule[0pt]\contentspage} +\titlecontents{subsection}[2cm] + {} + {\psabody\contentslabel{1.5cm}} + {\psabody} + {\titlerule[0pt]\contentspage} + +% and remove sphinx's ToC overrides +\let\sphinxtableofcontentshook\relax + +% Sphinx/pdflatex does not pick up the chpater title format from titlesec +% So hook the environment to insert formatting in the index title +\renewenvironment{sphinxtheindex}{% + \clearpage + \let\ixtitle\indexname% + \renewcommand{\indexname}{\psahh \ixtitle}% + \phantomsection % needed as no chapter, section, ... created + \begin{theindex}% + \addcontentsline{toc}{chapter}{\ixtitle}% + }{\end{theindex}} + +% This is something of a hack to get consistent, and differentiated API element +% subtitles in the specification. Simple specs might have API elements at +% level 3 headings (subsections), and complex ones at level 4 (subsubsection). +% So using a section level for the subtitles will yield inconsistent results. +% +% psa-api-tool.py uses `rubric` nodes for these sections (so don't use rubric in +% API reference for other things?). Unfortunately, Sphinx does not copy +% docutils and emit a \rubric{} command, it just emits \subsubsection*{}. +% +% As that [starred] command is not used for other elements, we replaced the +% \subsubsection command to intercept these uses and divert them to \rubric{}. +% We can then define \rubric{} as we wish - A bold 10pt runin for the main +% document text, and the original \subsubsection*{} in the appendix. +% +% Older versions of Sphinx directly use \paragraph{} for rubric, so +% also intercept level 5 headings and treat as rubric +% +% Heading 5 is used for all api subtitles +\newcommand{\subtitlett}[1]{{\normalfont\ttfamily #1}} +\newcommand{\apisubtitle}[1]{{\let\sphinxstyleliteralintitle\subtitlett #1}} +\titleformat{\paragraph} + {\psasubtitle} + {} + {0.5em}{\apisubtitle}{} +\titlespacing{\paragraph}{0pt}{*2}{4pt} + +\makeatletter +\let\oldsubsubsection\subsubsection +\renewcommand{\subsubsection} + % Only intercept rubrics in the main section + {\@ifstar{\IfAppendix{\oldsubsubsection*}{\paragraph*}}{\oldsubsubsection}} +\makeatother + +% Format lineblock text (consecutive lines prefixed with |) as a paragraph +% with forced line breaks +\renewenvironment{DUlineblock}[1]{% + \renewcommand{\item}[1][]{\par \renewcommand{\item}[1][]{\\}}% + \setlength{\leftmargin}{#1}% + \raggedright% +}{} + +% Set up item lists, enumerations and definition lists + +% Define spacing for lists +\setlist[1]{topsep=2pt, partopsep=0pt, itemsep=2pt, parsep=3pt plus 1pt minus 1pt} +\setlist[2]{topsep=2pt, partopsep=0pt, itemsep=1pt, parsep=1pt} +\setlist[3]{topsep=2pt, partopsep=0pt, itemsep=1pt, parsep=1pt} + +% Do not use multicols environment for hlist directive, but keep the compactness +\renewenvironment{multicols}[1]{\begingroup}{\endgroup} + +% Arabic, alpha, roman for level 1-3 +% New versions of sphinx ignore this and set the formatting based on the +% source text +\setlist[enumerate,1]{label=\arabic*.} +\setlist[enumerate,2]{label=\alph*.} +\setlist[enumerate,3]{label=\roman*.} + +% Bullet, em-dash, and circle for level 1-3 +\setlist[itemize,1]{label=$\bullet$} +\setlist[itemize,2]{label=---} +\setlist[itemize,3]{label=$\circ$} + +% Remove Sphinx hack for formatting multiple terms in definition list +% It forces the list formatting, and breaks the styling done with enumitem +\renewcommand\sphinxlineitem[2]{\item[#1]\leavevmode#2}% + +% Define standard definition list format +\def\termmargin {13ex} +\def\termindent {2ex} +\def\termspace {1ex} + +\setlist[description]{% + style=nextline,% + labelindent=\termindent, labelwidth=!, labelsep=\termspace,% + itemindent=0ex, leftmargin=\termmargin,% + font=\psabody,% + topsep=3pt, partopsep=0pt, itemsep=2pt, parsep=3pt% +} + +% Define API subitem definition list format +% This displays as a grid definition list, almost table-like +% psa-api-tool.py wraps the subitem lists in a apisubitem environment - so +% we can define that environment to set the description format +\def\apiitemwidth {30ex} +\def\apiitemindent { 0ex} +\def\apiitemspace {.5ex} + +\newenvironment{sphinxclassapisubitem} + {\setlist[description]{% + style=nextline,% + labelindent=\apiitemindent, labelwidth=\apiitemwidth,% + labelsep=\apiitemspace, itemindent=0ex, leftmargin=!,% + font=\psabody,% + topsep=3pt, partopsep=0pt, itemsep=2pt, parsep=3pt% + }} + {} + +% Define Threat card definition list format +\def\threatlabelwidth {20ex} +\def\threatlabelindent { 0ex} +\def\threatlabelspace {.5ex} + +\newenvironment{sphinxclassthreat} + {\setlist[description]{% + style=nextline,% + labelindent=\threatlabelindent, labelwidth=\threatlabelwidth,% + labelsep=\threatlabelspace, itemindent=0ex, leftmargin=!,% + font=\sphinxstylestrong,% + topsep=6pt plus 2pt minus 1pt, partopsep=0pt,% + itemsep=2pt, parsep=6pt plus 2pt minus 1pt% + }} + {} + +\newenvironment{sphinxclassriskrow} + {\renewcommand{\arraystretch}{1.2}% + \setlength\tabcolsep{0pt}% + \def\sphinxattableend{}% + \vskip\dimexpr-\parskip-\baselineskip\relax% + } + {} diff --git a/tools/templates/psa-api-2026/sphinx-templates/indextoc.html b/tools/templates/psa-api-2026/sphinx-templates/indextoc.html new file mode 100644 index 00000000..549e3123 --- /dev/null +++ b/tools/templates/psa-api-2026/sphinx-templates/indextoc.html @@ -0,0 +1,8 @@ +<!-- +SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +SPDX-License-Identifier: Apache-2.0 +--> + +<ul> +<li class="toctree-l1"><a class="reference internal" href="{{ pathto("psa_c-identifiers.html", 1) }}">Index of API elements</a></li> +</ul> diff --git a/tools/templates/psa-api-2026/sphinx-templates/toc.html b/tools/templates/psa-api-2026/sphinx-templates/toc.html new file mode 100644 index 00000000..3f7916bd --- /dev/null +++ b/tools/templates/psa-api-2026/sphinx-templates/toc.html @@ -0,0 +1,13 @@ +<!-- +SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +SPDX-License-Identifier: Apache-2.0 +--> + +<h3><a href="{{ pathto(master_doc) }}">{{ dochtmltitle }}</a></h3> +Version {{ docrelease }}<br/> +{{ docstatus }}<br/> +{{ docdate }}<br/> +<hr /> +<b><span class='issue'>Unofficial publication</span></b><br/>This is an open-source build +<hr /> +{{ toctree() }} diff --git a/tools/templates/psa-api-2026/template-conf.py b/tools/templates/psa-api-2026/template-conf.py new file mode 100644 index 00000000..e8c70eb6 --- /dev/null +++ b/tools/templates/psa-api-2026/template-conf.py @@ -0,0 +1,99 @@ +# SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +# SPDX-License-Identifier: Apache-2.0 + +# -*- coding: utf-8 -*- +# +# Adjust or reset the template_info dictionary with customized +# sphinx configurations for this template + +template_info['logo_file'] = 'logo' +template_info['html_theme'] = 'alabaster' +template_info['html_css_files'] = [ + ('https://fonts.googleapis.com', { 'rel': 'preconnect' }), + ('https://fonts.gstatic.com', { 'rel': 'preconnect', 'crossorigin': None }), + ('https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,300;0,400;1,300;1,400&family=Roboto+Mono:ital,wght@0,300;0,400;1,300&display=swap', { 'rel': 'stylesheet' }), +] +template_info['mathjax3_config'] = { + 'chtml': { + 'scale': 0.9, + 'mtextInheritFont': False, + 'mtextFont': "Roboto", + } +} +template_info['latex_pointsize'] = '11pt' +template_info['latex_fonts']= [ + r'\usepackage[scale=.95,sfdefault]{roboto}', + r'\usepackage[scale=.76]{roboto-mono}', + ] +template_info['latex_sphinxsetup'] = [ + # Reduce margins + 'hmargin={2cm,2cm}', + 'vmargin={2.5cm, 3cm}', + 'marginpar=1.27cm', + # Format the verbatim blocks + 'verbatimwithframe=true', + 'verbatimsep=3pt', + 'VerbatimBorderColor={rgb}{0.9,0.9,0.9}', + 'verbatimborder=0.5pt', + 'VerbatimColor={rgb}{0.97,0.97,0.97}', + # format hyperlink color + 'InnerLinkColor={rgb}{0.5,0,0.59}', + 'OuterLinkColor={rgb}{0.5,0,0.59}', + # format admonitions + 'noteBorderColor={rgb}{0.667,0.667,0.667}', + 'warningBorderColor={rgb}{.75,0.5,0.5}', + 'warningborder=2pt', + # Use attention admonition for the front page banner + 'attentionBorderColor={rgb}{.8,.8,0}', + 'attentionBgColor={rgb}{1,1,.7}', + 'attentionborder=1pt', + # Use error admonition for rationale boxes + 'errorBorderColor={rgb}{.5,.75,.5}', + 'errorBgColor={rgb}{.9,.95,.9}', + 'errorborder=1pt', + # Use hint admonition for comment boxes + 'hintBorderColor={rgb}{.6,.6,.6}', + 'hintBgColor={rgb}{.97,.97,.97}', + 'hintborder=0pt', + 'hintTextColor={rgb}{.4,.4,.4}', + # Use the normal font for headings + 'HeaderFamily=\\normalfont\\mdseries', +] +template_info['latex_table_style'] = ['booktabs','nocolorrows'] +template_info['graphviz_dot_args'] = [ + '-Gfontname=Lato', + '-Gfontsize=12', + '-Nfontname=Lato', + '-Nfontsize=12', + '-Efontname=Lato', + '-Efontsize=12' +] + +def make_doc_filename(info, id, title, version, status): + doc_parts = [info.get('filetitle',title), version] + status = status.split(' ')[-1].lower() + if status != 'release': + doc_parts += [status] + return '-'.join(doc_parts) +template_info['make_filename'] = make_doc_filename + +template_info['front_sections'] = [ + 'introduction', + 'api-status', + 'feedback', + 'audience', + 'license', + 'references', + 'terms', + 'abbreviations', + 'release-info', + 'todos', + ] +template_info['numfig_sec_depth'] = 1 +template_info['page_break'] = 'chapter' + +doc_info.setdefault('author', 'The PSA Certified API contributors') +doc_info.setdefault('copyright', 'The PSA Certified API contributors') +doc_info.setdefault('feedback', 'visit :url:`github.com/arm-software/psa-api/issues`' + + ' to create a new issue at the PSA Certified API GitHub project') +doc_info.setdefault('license', 'psa-certified-api-license') diff --git a/tools/templates/psa-api-2026/title-page.rst b/tools/templates/psa-api-2026/title-page.rst new file mode 100644 index 00000000..3954db10 --- /dev/null +++ b/tools/templates/psa-api-2026/title-page.rst @@ -0,0 +1,49 @@ +.. SPDX-FileCopyrightText: Copyright 2018-2026 Arm Limited +.. SPDX-License-Identifier: CC-BY-SA-4.0 AND LicenseRef-Patent-license + +.. only:: html + + .. template-image:: logo.svg + :alt: [logo]] + :class: titlelogo + +============= +|docrsttitle| +============= + +.. raw:: latex + + \psabody\color{psaink} + + \begin{psatitle} + +.. csv-table:: + :class: titletable borderless + :align: left + + Version:, |docreleasefull| + Quality:, |docquality| + Status:, |docstatus| + Date of Issue:, |docdate| + +.. raw:: latex + + \psatitlecopyright + +.. csv-table:: + :align: center + :class: standard + + :issue:`Unofficial publication`: This is an open-source build of the documentation + +.. insert-banner:: + +.. raw:: latex + + \end{psatitle} + +.. only:: html + + .. insert-section:: Contents + :not-in-toc: + :keep-if-empty: