architecture: describe subkeys

Adds a new section on subkeys and a note on subkeys with REE-FS TAs.

Acked-by: Jerome Forissier <jerome.forissier@linaro.org>
Acked-by: Etienne Carriere <etienne.carriere@linaro.org>
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
diff --git a/architecture/index.rst b/architecture/index.rst
index ad3c955..8ae5205 100644
--- a/architecture/index.rst
+++ b/architecture/index.rst
@@ -13,6 +13,7 @@
    porting_guidelines
    secure_boot
    secure_storage
+   subkeys
    trusted_applications
    virtualization
    spmc
diff --git a/architecture/subkeys.rst b/architecture/subkeys.rst
new file mode 100644
index 0000000..9ca6abd
--- /dev/null
+++ b/architecture/subkeys.rst
@@ -0,0 +1,211 @@
+.. _subkeys:
+
+#######
+Subkeys
+#######
+Subkeys is an OP-TEE-specific implementation to provide a public key 
+hierarchy. Subkeys can be delegated to allow different actors to sign
+different TAs without sharing a private key.
+
+The first key in the chain is verified using a root key. Example Subkey
+hierarchy:
+
+
+.. uml::
+	:width: 800
+
+	object "Root key" as root
+	object "First-level subkey" as first
+	object "Second-level subkey" as second
+
+	object root {
+		PublicKey
+	}
+
+	object first {
+		Signature
+		UUID
+		PublicKey
+	}
+	
+	object second {
+		Signature
+		UUID
+		PublicKey
+	}
+
+	root -> first
+	first -> second
+
+Each subkey defines a UUIDv5 namespace [#f1]_ to which another signed
+subkey or TA must belong. This avoids that one subkey can be used to sign
+TAs which should be signed with a different key. Since the UUIDs are
+restricted by this there is also a special kind of subkey, called identity
+subkey, which uses the same UUID as the TA it is supposed to sign.
+
+A subkey consists of two files, a private key pair in a .pem file and the
+signed public key in a .bin file. Subkeys reuse the signed header (SHDR)
+format used for signed TAs, followed by a payload holding a public key and
+UUID among other fields. A subkey is formatted with all fields in
+little endian as:
+
++-----------+-------------------+---------------------+-----------------------+
+| Size in   | Field Name        | Protected by field  |                       |
+| bytes     |                   |                     |                       |
++-----------+-------------------+---------------------+-----------------------+
+| .. centered:: Signed header (struct shdr)           |                       |
++-----------+-------------------+---------------------+-----------------------+
+| 4         |   magic           |  hash               | 0x4f545348            |
++-----------+-------------------+---------------------+-----------------------+
+| 4         |   img_type        |  hash               | 3, SHDR_SUBKEY        |
++-----------+-------------------+---------------------+-----------------------+
+| 4         |   img_size        |  hash               |                       |
++-----------+-------------------+---------------------+-----------------------+
+| 4         |   algo            |  hash               | Signature algorithm,  |
+|           |                   |                     | GP TEE_ALG_*          |
++-----------+-------------------+---------------------+-----------------------+
+| 4         |   hash_size       |  hash               |                       |
++-----------+-------------------+---------------------+-----------------------+
+| 4         |   sig_size        |  hash               |                       |
++-----------+-------------------+---------------------+-----------------------+
+| hash_size |   hash            |  sig                |                       |
++-----------+-------------------+---------------------+-----------------------+
+| sig_size  |   sig             |  previous pub key   | Root key or a subkey  |
+|           |                   |                     | higher up in the      |
+|           |                   |                     | chain                 |
++-----------+-------------------+---------------------+-----------------------+
+| .. centered:: Subkey header (struct shdr_subkey)    |                       |
++-----------+-------------------+---------------------+-----------------------+
+| 16        |   UUID            |  hash               | UUIDv5 namespace for  |
+|           |                   |                     | next subkey or TA     |
++-----------+-------------------+---------------------+-----------------------+
+| 4         |   name_size       |  hash               | Size of the UUIDv5    |
+|           |                   |                     | name for the          |
+|           |                   |                     | next subkey or TA,    |
+|           |                   |                     | 0 for identiy subkeys |
++-----------+-------------------+---------------------+-----------------------+
+| 4         |   subkey_version  |  hash               |                       |
++-----------+-------------------+---------------------+-----------------------+
+| 4         |   max_depth       |  hash               |                       |
++-----------+-------------------+---------------------+-----------------------+
+| 4         |   algo            |  hash               | Signature algorithm   |
+|           |                   |                     | for the next          |
+|           |                   |                     | subkey or TA          |
++-----------+-------------------+---------------------+-----------------------+
+| 4         |   attr_count      |  hash               |                       |
++-----------+-------------------+---------------------+-----------------------+
+|           | .. centered:: Subkey attrs * attr_count | Attributes of the     |
+|           |                                         | public key in this    |
+|           |                                         | subkey                |
++-----------+-------------------+---------------------+-----------------------+
+| 4         |   id              |  hash               | GP TEE_ATTR_*         |
++-----------+-------------------+---------------------+-----------------------+
+| 4         |   offs            |  hash               |                       |
++-----------+-------------------+---------------------+-----------------------+
+| 4         |   size            |  hash               |                       |
++-----------+-------------------+---------------------+-----------------------+
+| opaque data padding up this   |  hash               | The subkey attributes |
+| binary to img_size            |                     | above point into      |
+|                               |                     | this area using       |
+|                               |                     | offset and size       |
++-------------------------------+---------------------+-----------------------+
+
+All subkeys included in the subkey hierarchy are added in front when a TA
+is signed using a subkey. For example, if a TA is signed using the
+second-level subkey above it would look like this:
+
++------------------+----------------------+-----------------------------------+
+| Size in bytes    | Binary               |                                   |
++------------------+----------------------+-----------------------------------+
+| first.img_size   | First-level subkey     | Signed by Root key              |
++------------------+----------------------+-----------------------------------+
+| first.name_size  | UUIDv5 name string   | Not signed, used to prove that    |
+|                  | for the next subkey  | the next UUID is in the namespace |
+|                  |                      | of the First-level subkey.        |
+|                  |                      | This size is from "name_size"     |
+|                  |                      | of the previous subkey            |
+|                  |                      | (First-level).                    |
++------------------+----------------------+-----------------------------------+
+| second.img_size  | Second-level subkey  | Signed by First-level subkey      |
++------------------+----------------------+-----------------------------------+
+| second.name_size | UUIDv5 name string   | Not signed used to prove that     |
+|                  | for the TA           | the next UUID is in the namespace |
+|                  |                      | of the Second-level subkey.       |
+|                  |                      | This size is from "name_size"     |
+|                  |                      | of the previous subkey            |
+|                  |                      | (Second-level).                   |
++------------------+----------------------+-----------------------------------+
+| second.img_size  | TA                   | Signed by Second-level subkey     |
++------------------+----------------------+-----------------------------------+
+
+The signed TA binary is self-contained with all the public keys
+needed for verification included, except the public root key which is
+embedded in the TEE core binary.
+
+The UUIDv5 name string is a separate field between subkeys and the next
+subkey or TA to allow a subkey to be used to sign more than one other
+subkey or TA.
+
+A signed TA or subkey can be inspected using the sign_encrypt.py script,
+for example::
+
+    $ scripts/sign_encrypt.py display --in 5c206987-16a3-59cc-ab0f-64b9cfc9e758.ta
+    Subkey
+     struct shdr
+      magic:      0x4f545348
+      img_type:   3 (SHDR_SUBKEY)
+      img_size:   320 bytes
+      algo:       0x70414930 (TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256)
+      hash_size:  32 bytes
+      sig_size:   256 bytes
+      hash:       f573f329fe77be686ce71647909c4ea35b5e1cd7de86369bd7d9fca31f6a4d65
+     struct shdr_subkey
+      uuid:       f04fa996-148a-453c-b037-1dcfbad120a6
+      name_size:  64
+      subkey_version: 1
+      max_depth:  4
+      algo:       0x70414930 (TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256)
+      attr_count: 2
+      next name:  "mid_level_subkey"
+    Next header at offset: 692 (0x2b4)
+    Subkey
+     struct shdr
+      magic:      0x4f545348
+      img_type:   3 (SHDR_SUBKEY)
+      img_size:   320 bytes
+      algo:       0x70414930 (TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256)
+      hash_size:  32 bytes
+      sig_size:   256 bytes
+      hash:       233a6dcf1a2cf69e50cde8e20c4129157da707c76fa86ce12ee31037edef02d7
+     struct shdr_subkey
+      uuid:       1a5948c5-1aa0-518c-86f4-be6f6a057b16
+      name_size:  64
+      subkey_version: 1
+      max_depth:  3
+      algo:       0x70414930 (TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256)
+      attr_count: 2
+      next name:  "subkey1_ta"
+    Next header at offset: 1384 (0x568)
+    Bootstrap TA
+     struct shdr
+      magic:      0x4f545348
+      img_type:   1 (SHDR_BOOTSTRAP_TA)
+      img_size:   84576 bytes
+      algo:       0x70414930 (TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256)
+      hash_size:  32 bytes
+      sig_size:   256 bytes
+      hash:       ea31ac7dc2cc06a9dc2853cd791dd00f784b5edc062ecfa274deeb66589b4ca5
+     struct shdr_bootstrap_ta
+      uuid:       5c206987-16a3-59cc-ab0f-64b9cfc9e758
+      ta_version: 0
+     TA offset:  1712 (0x6b0) bytes
+     TA size:    84576 (0x14a60) bytes
+
+
+.. rubric:: Footnotes
+
+.. [#f1] UUIDv5 and namespaces are described in
+	`RFC4122 <https://datatracker.ietf.org/doc/html/rfc4122>`_.
+	Note that OP-TEE uses a truncated SHA-512 instead of the
+        weak SHA-1 hash when when deriving a new UUID from a
+        namespace and name.
diff --git a/architecture/trusted_applications.rst b/architecture/trusted_applications.rst
index 9ee1ef4..fc51800 100644
--- a/architecture/trusted_applications.rst
+++ b/architecture/trusted_applications.rst
@@ -279,6 +279,23 @@
                        <struct shdr_encrypted_ta> || <nonce> || <tag> ||
                        <ciphertext>
 
+Verifying with Subkeys
+----------------------
+A TA can be verified using a subkey or a chain of subkeys. This allows
+delegation of TA signing without distributing the root key. TAs signed with
+a subkey are confined to the UUID-V5 namespace of the subkey to avoid TA
+UUID clashes with different subkeys.
+
+SHDR_SUBKEY is a type of header which enables chains of public keys.  The
+public root key is used to verify the first public subkey, which then is
+used to verify the next public subkey and so on.
+
+The TA is finally verified using the last subkey. All these headers are
+added in front of the TA binary so everything needed to verify the TA is
+available when it's loaded into memory.
+
+For details on subkeys see also :ref:`_subkeys`
+
 Loading REE-FS TA
 -----------------
 A REE TA is loaded into shared memory using a series or RPC in