Jens Wiklander | e501039 | 2022-10-14 08:58:27 +0200 | [diff] [blame^] | 1 | .. _subkeys: |
| 2 | |
| 3 | ####### |
| 4 | Subkeys |
| 5 | ####### |
| 6 | Subkeys is an OP-TEE-specific implementation to provide a public key |
| 7 | hierarchy. Subkeys can be delegated to allow different actors to sign |
| 8 | different TAs without sharing a private key. |
| 9 | |
| 10 | The first key in the chain is verified using a root key. Example Subkey |
| 11 | hierarchy: |
| 12 | |
| 13 | |
| 14 | .. uml:: |
| 15 | :width: 800 |
| 16 | |
| 17 | object "Root key" as root |
| 18 | object "First-level subkey" as first |
| 19 | object "Second-level subkey" as second |
| 20 | |
| 21 | object root { |
| 22 | PublicKey |
| 23 | } |
| 24 | |
| 25 | object first { |
| 26 | Signature |
| 27 | UUID |
| 28 | PublicKey |
| 29 | } |
| 30 | |
| 31 | object second { |
| 32 | Signature |
| 33 | UUID |
| 34 | PublicKey |
| 35 | } |
| 36 | |
| 37 | root -> first |
| 38 | first -> second |
| 39 | |
| 40 | Each subkey defines a UUIDv5 namespace [#f1]_ to which another signed |
| 41 | subkey or TA must belong. This avoids that one subkey can be used to sign |
| 42 | TAs which should be signed with a different key. Since the UUIDs are |
| 43 | restricted by this there is also a special kind of subkey, called identity |
| 44 | subkey, which uses the same UUID as the TA it is supposed to sign. |
| 45 | |
| 46 | A subkey consists of two files, a private key pair in a .pem file and the |
| 47 | signed public key in a .bin file. Subkeys reuse the signed header (SHDR) |
| 48 | format used for signed TAs, followed by a payload holding a public key and |
| 49 | UUID among other fields. A subkey is formatted with all fields in |
| 50 | little endian as: |
| 51 | |
| 52 | +-----------+-------------------+---------------------+-----------------------+ |
| 53 | | Size in | Field Name | Protected by field | | |
| 54 | | bytes | | | | |
| 55 | +-----------+-------------------+---------------------+-----------------------+ |
| 56 | | .. centered:: Signed header (struct shdr) | | |
| 57 | +-----------+-------------------+---------------------+-----------------------+ |
| 58 | | 4 | magic | hash | 0x4f545348 | |
| 59 | +-----------+-------------------+---------------------+-----------------------+ |
| 60 | | 4 | img_type | hash | 3, SHDR_SUBKEY | |
| 61 | +-----------+-------------------+---------------------+-----------------------+ |
| 62 | | 4 | img_size | hash | | |
| 63 | +-----------+-------------------+---------------------+-----------------------+ |
| 64 | | 4 | algo | hash | Signature algorithm, | |
| 65 | | | | | GP TEE_ALG_* | |
| 66 | +-----------+-------------------+---------------------+-----------------------+ |
| 67 | | 4 | hash_size | hash | | |
| 68 | +-----------+-------------------+---------------------+-----------------------+ |
| 69 | | 4 | sig_size | hash | | |
| 70 | +-----------+-------------------+---------------------+-----------------------+ |
| 71 | | hash_size | hash | sig | | |
| 72 | +-----------+-------------------+---------------------+-----------------------+ |
| 73 | | sig_size | sig | previous pub key | Root key or a subkey | |
| 74 | | | | | higher up in the | |
| 75 | | | | | chain | |
| 76 | +-----------+-------------------+---------------------+-----------------------+ |
| 77 | | .. centered:: Subkey header (struct shdr_subkey) | | |
| 78 | +-----------+-------------------+---------------------+-----------------------+ |
| 79 | | 16 | UUID | hash | UUIDv5 namespace for | |
| 80 | | | | | next subkey or TA | |
| 81 | +-----------+-------------------+---------------------+-----------------------+ |
| 82 | | 4 | name_size | hash | Size of the UUIDv5 | |
| 83 | | | | | name for the | |
| 84 | | | | | next subkey or TA, | |
| 85 | | | | | 0 for identiy subkeys | |
| 86 | +-----------+-------------------+---------------------+-----------------------+ |
| 87 | | 4 | subkey_version | hash | | |
| 88 | +-----------+-------------------+---------------------+-----------------------+ |
| 89 | | 4 | max_depth | hash | | |
| 90 | +-----------+-------------------+---------------------+-----------------------+ |
| 91 | | 4 | algo | hash | Signature algorithm | |
| 92 | | | | | for the next | |
| 93 | | | | | subkey or TA | |
| 94 | +-----------+-------------------+---------------------+-----------------------+ |
| 95 | | 4 | attr_count | hash | | |
| 96 | +-----------+-------------------+---------------------+-----------------------+ |
| 97 | | | .. centered:: Subkey attrs * attr_count | Attributes of the | |
| 98 | | | | public key in this | |
| 99 | | | | subkey | |
| 100 | +-----------+-------------------+---------------------+-----------------------+ |
| 101 | | 4 | id | hash | GP TEE_ATTR_* | |
| 102 | +-----------+-------------------+---------------------+-----------------------+ |
| 103 | | 4 | offs | hash | | |
| 104 | +-----------+-------------------+---------------------+-----------------------+ |
| 105 | | 4 | size | hash | | |
| 106 | +-----------+-------------------+---------------------+-----------------------+ |
| 107 | | opaque data padding up this | hash | The subkey attributes | |
| 108 | | binary to img_size | | above point into | |
| 109 | | | | this area using | |
| 110 | | | | offset and size | |
| 111 | +-------------------------------+---------------------+-----------------------+ |
| 112 | |
| 113 | All subkeys included in the subkey hierarchy are added in front when a TA |
| 114 | is signed using a subkey. For example, if a TA is signed using the |
| 115 | second-level subkey above it would look like this: |
| 116 | |
| 117 | +------------------+----------------------+-----------------------------------+ |
| 118 | | Size in bytes | Binary | | |
| 119 | +------------------+----------------------+-----------------------------------+ |
| 120 | | first.img_size | First-level subkey | Signed by Root key | |
| 121 | +------------------+----------------------+-----------------------------------+ |
| 122 | | first.name_size | UUIDv5 name string | Not signed, used to prove that | |
| 123 | | | for the next subkey | the next UUID is in the namespace | |
| 124 | | | | of the First-level subkey. | |
| 125 | | | | This size is from "name_size" | |
| 126 | | | | of the previous subkey | |
| 127 | | | | (First-level). | |
| 128 | +------------------+----------------------+-----------------------------------+ |
| 129 | | second.img_size | Second-level subkey | Signed by First-level subkey | |
| 130 | +------------------+----------------------+-----------------------------------+ |
| 131 | | second.name_size | UUIDv5 name string | Not signed used to prove that | |
| 132 | | | for the TA | the next UUID is in the namespace | |
| 133 | | | | of the Second-level subkey. | |
| 134 | | | | This size is from "name_size" | |
| 135 | | | | of the previous subkey | |
| 136 | | | | (Second-level). | |
| 137 | +------------------+----------------------+-----------------------------------+ |
| 138 | | second.img_size | TA | Signed by Second-level subkey | |
| 139 | +------------------+----------------------+-----------------------------------+ |
| 140 | |
| 141 | The signed TA binary is self-contained with all the public keys |
| 142 | needed for verification included, except the public root key which is |
| 143 | embedded in the TEE core binary. |
| 144 | |
| 145 | The UUIDv5 name string is a separate field between subkeys and the next |
| 146 | subkey or TA to allow a subkey to be used to sign more than one other |
| 147 | subkey or TA. |
| 148 | |
| 149 | A signed TA or subkey can be inspected using the sign_encrypt.py script, |
| 150 | for example:: |
| 151 | |
| 152 | $ scripts/sign_encrypt.py display --in 5c206987-16a3-59cc-ab0f-64b9cfc9e758.ta |
| 153 | Subkey |
| 154 | struct shdr |
| 155 | magic: 0x4f545348 |
| 156 | img_type: 3 (SHDR_SUBKEY) |
| 157 | img_size: 320 bytes |
| 158 | algo: 0x70414930 (TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256) |
| 159 | hash_size: 32 bytes |
| 160 | sig_size: 256 bytes |
| 161 | hash: f573f329fe77be686ce71647909c4ea35b5e1cd7de86369bd7d9fca31f6a4d65 |
| 162 | struct shdr_subkey |
| 163 | uuid: f04fa996-148a-453c-b037-1dcfbad120a6 |
| 164 | name_size: 64 |
| 165 | subkey_version: 1 |
| 166 | max_depth: 4 |
| 167 | algo: 0x70414930 (TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256) |
| 168 | attr_count: 2 |
| 169 | next name: "mid_level_subkey" |
| 170 | Next header at offset: 692 (0x2b4) |
| 171 | Subkey |
| 172 | struct shdr |
| 173 | magic: 0x4f545348 |
| 174 | img_type: 3 (SHDR_SUBKEY) |
| 175 | img_size: 320 bytes |
| 176 | algo: 0x70414930 (TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256) |
| 177 | hash_size: 32 bytes |
| 178 | sig_size: 256 bytes |
| 179 | hash: 233a6dcf1a2cf69e50cde8e20c4129157da707c76fa86ce12ee31037edef02d7 |
| 180 | struct shdr_subkey |
| 181 | uuid: 1a5948c5-1aa0-518c-86f4-be6f6a057b16 |
| 182 | name_size: 64 |
| 183 | subkey_version: 1 |
| 184 | max_depth: 3 |
| 185 | algo: 0x70414930 (TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256) |
| 186 | attr_count: 2 |
| 187 | next name: "subkey1_ta" |
| 188 | Next header at offset: 1384 (0x568) |
| 189 | Bootstrap TA |
| 190 | struct shdr |
| 191 | magic: 0x4f545348 |
| 192 | img_type: 1 (SHDR_BOOTSTRAP_TA) |
| 193 | img_size: 84576 bytes |
| 194 | algo: 0x70414930 (TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256) |
| 195 | hash_size: 32 bytes |
| 196 | sig_size: 256 bytes |
| 197 | hash: ea31ac7dc2cc06a9dc2853cd791dd00f784b5edc062ecfa274deeb66589b4ca5 |
| 198 | struct shdr_bootstrap_ta |
| 199 | uuid: 5c206987-16a3-59cc-ab0f-64b9cfc9e758 |
| 200 | ta_version: 0 |
| 201 | TA offset: 1712 (0x6b0) bytes |
| 202 | TA size: 84576 (0x14a60) bytes |
| 203 | |
| 204 | |
| 205 | .. rubric:: Footnotes |
| 206 | |
| 207 | .. [#f1] UUIDv5 and namespaces are described in |
| 208 | `RFC4122 <https://datatracker.ietf.org/doc/html/rfc4122>`_. |
| 209 | Note that OP-TEE uses a truncated SHA-512 instead of the |
| 210 | weak SHA-1 hash when when deriving a new UUID from a |
| 211 | namespace and name. |