blob: 48abc6120313e5ff78c5b12ce469ac77b3dc67c2 [file] [log] [blame]
Joakim Bech8e5c5b32018-10-25 08:18:32 +02001.. _build_trusted_applications:
2
3####################
4Trusted Applications
5####################
6This document tells how to implement a Trusted Application for OP-TEE, using
7OP-TEE's so called `TA-devkit` to both build and sign the Trusted Application
8binary. In this document, a `Trusted Application` running in the OP-TEE os is
Joakim Beche58b15c2020-04-15 10:48:41 +02009referred to as a `TA`. Note that in the default setup a private test key is
Markus S. Wamser1aa72d82019-02-28 15:21:08 +010010distributed along with the :ref:`optee_os` source is used for signing Trusted
Joakim Beche58b15c2020-04-15 10:48:41 +020011Applications. See TASign_ for more details, including offline signing of TAs.
Joakim Bech8e5c5b32018-10-25 08:18:32 +020012
13TA Mandatory files
14******************
15The Makefile for a Trusted Application must be written to rely on OP-TEE
16TA-devkit resources in order to successfully build the target application.
17TA-devkit is built when one builds :ref:`optee_os`.
18
19.. todo::
20
21 Joakim: We need to add CMake instructions also.
22
23To build a TA, one must provide:
24
25 - **Makefile**, a make file that should set some configuration variables and
26 include the TA-devkit make file.
27
28 - **sub.mk**, a make file that lists the sources to build (local source
29 files, subdirectories to parse, source file specific build directives).
30
31 - **user_ta_header_defines.h**, a specific ANSI-C header file to define most
32 of the TA properties.
33
Markus S. Wamser030dae02019-08-07 15:36:36 +020034 - An implementation of at least the TA entry points, as extern functions:
Joakim Bech8e5c5b32018-10-25 08:18:32 +020035 ``TA_CreateEntryPoint()``, ``TA_DestroyEntryPoint()``,
36 ``TA_OpenSessionEntryPoint()``, ``TA_CloseSessionEntryPoint()``,
37 ``TA_InvokeCommandEntryPoint()``
38
39TA file layout example
40======================
41As an example, :ref:`hello_world` looks like this:
42
43.. code-block:: none
44
45 hello_world/
46 ├── ...
47 └── ta
48 ├── Makefile BINARY=<uuid>
49 ├── Android.mk Android way to invoke the Makefile
50 ├── sub.mk srcs-y += hello_world_ta.c
51 ├── include
52 │   └── hello_world_ta.h Header exported to non-secure: TA commands API
Markus S. Wamser030dae02019-08-07 15:36:36 +020053 ├── hello_world_ta.c Implementation of TA entry points
Joakim Bech8e5c5b32018-10-25 08:18:32 +020054 └── user_ta_header_defines.h TA_UUID, TA_FLAGS, TA_DATA/STACK_SIZE, ...
55
56TA Makefile Basics
57******************
58Required variables
59==================
Markus S. Wamser030dae02019-08-07 15:36:36 +020060The main TA-devkit make file is located in :ref:`optee_os` at
Joakim Bech8e5c5b32018-10-25 08:18:32 +020061``ta/mk/ta_dev_kit.mk``. The make file supports make targets such as ``all`` and
62``clean`` to build a TA or a library and clean the built objects.
63
64The make file expects a couple of configuration variables:
65
66TA_DEV_KIT_DIR
Markus S. Wamser030dae02019-08-07 15:36:36 +020067 Base directory of the TA-devkit. Used by the TA-devkit itself to locate its tools.
Joakim Bech8e5c5b32018-10-25 08:18:32 +020068
69BINARY and LIBNAME
70 These are exclusive, meaning that you cannot use both at the same time. If
71 building a TA, ``BINARY`` shall provide the TA filename used to load the TA.
72 The built and signed TA binary file will be named ``${BINARY}.ta``. In
73 native OP-TEE, it is the TA UUID, used by tee-supplicant to identify TAs. If
74 one is building a static library (that will be later linked by a TA), then
75 ``LIBNAME`` shall provide the name of the library. The generated library
76 binary file will be named ``lib${LIBNAME}.a``
77
78CROSS_COMPILE and CROSS_COMPILE32
79 Cross compiler for the TA or the library source files. ``CROSS_COMPILE32``
80 is optional. It allows to target AArch32 builds on AArch64 capable systems.
81 On AArch32 systems, ``CROSS_COMPILE32`` defaults to ``CROSS_COMPILE``.
82
83Optional variables
84==================
85Some optional configuration variables can be supported, for example:
86
87O
88 Base directory for build objects filetree. If not set, TA-devkit defaults to
89 **./out** from the TA source tree base directory.
90
91Example Makefile
92================
93A typical Makefile for a TA looks something like this
94
95.. code-block:: Makefile
96
97 # Append specific configuration to the C source build (here log=info)
98 # The UUID for the Trusted Application
99 BINARY=8aaaf200-2450-11e4-abe2-0002a5d5c51b
100
101 # Source the TA-devkit make file
102 include $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk
103
104.. _build_trusted_applications_submk:
105
106sub.mk directives
107=================
108The make file expects that current directory contains a file ``sub.mk`` that is
109the entry point for listing the source files to build and other specific build
110directives. Here are a couple of examples of directives one can implement in a
111sub.mk make file:
112
113.. code-block:: Makefile
114
115 # Adds /hello_world_ta.c from current directory to the list of the source
116 # file to build and link.
117 srcs-y += hello_world_ta.c
118
119 # Includes path **./include/** from the current directory to the include
120 # path.
121 global-incdirs-y += include/
122
123 # Adds directive -Wno-strict-prototypes only to the file hello_world_ta.c
124 cflags-hello_world_ta.c-y += -Wno-strict-prototypes
125
126 # Removes directive -Wno-strict-prototypes from the build directives for
127 # hello_world_ta.c only.
128 cflags-remove-hello_world_ta.c-y += -Wno-strict-prototypes
129
130 # Adds the static library foo to the list of the linker directive -lfoo.
131 libnames += foo
132
133 # Adds the directory path to the libraries pathes list. Archive file
Markus S. Wamser030dae02019-08-07 15:36:36 +0200134 # libfoo.a is expected in this directory.
Joakim Bech8e5c5b32018-10-25 08:18:32 +0200135 libdirs += path/to/libfoo/install/directory
136
137 # Adds the static library binary to the TA build dependencies.
138 libdeps += path/to/greatlib/libgreatlib.a
139
140Android Build Environment
141*************************
142.. todo::
143
144 Joakim: Move this to the AOSP page?
145
146OP-TEE's TA-devkit supports building in an Android build environment. One can
147write an ``Android.mk`` file for the TA (stored side by side with the Makefile).
148Android's build system will parse the ``Android.mk`` file for the TA which in
149turn will parse a TA-devkit Android make file to locate TA build resources. Then
150the Android build will execute a ``make`` command to built the TA through its
151generic Makefile file.
152
153A typical ``Android.mk`` file for a TA looks like this (``Android.mk`` for
154:ref:`hello_world` is used as an example here).
155
156.. code-block:: Makefile
157
158 # Define base path for the TA sources filetree
159 LOCAL_PATH := $(call my-dir)
160
161 # Define the module name as the signed TA binary filename.
162 local_module := 8aaaf200-2450-11e4-abe2-0002a5d5c51b.ta
163
Markus S. Wamser030dae02019-08-07 15:36:36 +0200164 # Include the devkit Android make script
Joakim Bech8e5c5b32018-10-25 08:18:32 +0200165 include $(OPTEE_OS_DIR)/mk/aosp_optee.mk
166
167TA Mandatory Entry Points
168*************************
169A TA must implement a couple of mandatory entry points, these are:
170
171.. code-block:: c
172
173 TEE_Result TA_CreateEntryPoint(void)
174 {
175 /* Allocate some resources, init something, ... */
176 ...
177
178 /* Return with a status */
179 return TEE_SUCCESS;
180 }
181
182 void TA_DestroyEntryPoint(void)
183 {
184 /* Release resources if required before TA destruction */
185 ...
186 }
187
188 TEE_Result TA_OpenSessionEntryPoint(uint32_t ptype,
189 TEE_Param param[4],
190 void **session_id_ptr)
191 {
192 /* Check client identity, and alloc/init some session resources if any */
193 ...
194
195 /* Return with a status */
196 return TEE_SUCCESS;
197 }
198
199 void TA_CloseSessionEntryPoint(void *sess_ptr)
200 {
201 /* check client and handle session resource release, if any */
202 ...
203 }
204
205 TEE_Result TA_InvokeCommandEntryPoint(void *session_id,
206 uint32_t command_id,
207 uint32_t parameters_type,
208 TEE_Param parameters[4])
209 {
210 /* Decode the command and process execution of the target service */
211 ...
212
213 /* Return with a status */
214 return TEE_SUCCESS;
215 }
216
217.. _build_ta_properties:
218
219TA Properties
220*************
221Trusted Application properties shall be defined in a header file named
222``user_ta_header_defines.h``, which should contain:
223
224 - ``TA_UUID`` defines the TA uuid value
225 - ``TA_FLAGS`` define some of the TA properties
226 - ``TA_STACK_SIZE`` defines the RAM size to be reserved for TA stack
227 - ``TA_DATA_SIZE`` defines the RAM size to be reserved for TA heap (TEE_Malloc()
228 pool)
229
230Refer to :ref:`ta_properties` to understand how to configure these macros.
231
Markus S. Wamser1aa72d82019-02-28 15:21:08 +0100232.. hint::
233
234 UUIDs can be generated using python
235
236 .. code-block:: python
237
238 python -c 'import uuid; print(uuid.uuid4())'
239
240 or in most Linux systems using either
241
242 .. code-block:: bash
243
244 cat /proc/sys/kernel/random/uuid # Linux only
245 uuidgen # available from the util-linux package in most distributions
246
247
248
Joakim Bech8e5c5b32018-10-25 08:18:32 +0200249.. _user_ta_header_defines_h:
250
251Example of a property header file
252=================================
253
254.. code-block:: c
255
256 #ifndef USER_TA_HEADER_DEFINES_H
257 #define USER_TA_HEADER_DEFINES_H
258
259 #define TA_UUID
260 { 0x8aaaf200, 0x2450, 0x11e4, \
261 { 0xab, 0xe2, 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b} }
262
263 #define TA_FLAGS (TA_FLAG_EXEC_DDR | \
264 TA_FLAG_SINGLE_INSTANCE | \
265 TA_FLAG_MULTI_SESSION)
266 #define TA_STACK_SIZE (2 * 1024)
267 #define TA_DATA_SIZE (32 * 1024)
268
269 #define TA_CURRENT_TA_EXT_PROPERTIES \
270 { "gp.ta.description", USER_TA_PROP_TYPE_STRING, "Foo TA for some purpose." }, \
271 { "gp.ta.version", USER_TA_PROP_TYPE_U32, &(const uint32_t){ 0x0100 } }
272
273 #endif /* USER_TA_HEADER_DEFINES_H */
274
275.. note::
276
277 It is recommended to use the ``TA_CURRENT_TA_EXT_PROPERTIES`` as above to
278 define extra properties of the TA.
279
Markus S. Wamser1aa72d82019-02-28 15:21:08 +0100280.. note::
281
282 Generating a fresh UUID with suitable formatting for the header file can be
283 done using:
284
285 .. code-block:: python
286
287 python -c "import uuid; u=uuid.uuid4(); print(u); \
288 n = [', 0x'] * 11; \
289 n[::2] = ['{:12x}'.format(u.node)[i:i + 2] for i in range(0, 12, 2)]; \
290 print('\n' + '#define TA_UUID\n\t{ ' + \
291 '0x{:08x}'.format(u.time_low) + ', ' + \
292 '0x{:04x}'.format(u.time_mid) + ', ' + \
293 '0x{:04x}'.format(u.time_hi_version) + ', \\ \n\n\t\t{ ' + \
294 '0x{:02x}'.format(u.clock_seq_hi_variant) + ', ' + \
295 '0x{:02x}'.format(u.clock_seq_low) + ', ' + \
296 '0x' + ''.join(n) + '} }')"
297
298
Joakim Bech8e5c5b32018-10-25 08:18:32 +0200299Checking TA parameters
300**********************
301GlobalPlatforms TEE Client APIs ``TEEC_InvokeCommand()`` and
302``TEE_OpenSession()`` allow clients to invoke a TA with some invocation
303parameters: values or references to memory buffers. It is mandatory that TA's
304verify the parameters types before using the parameters themselves. For this a
305TA can rely on the macro ``TEE_PARAM_TYPE_GET(param_type, param_index)`` to get
306the type of a parameter and check its value according to the expected parameter.
307
308For example, if a TA expects that command ID 0 comes with ``params[0]`` being a
309input value, ``params[1]`` being a output value, and ``params[2]`` being a
310in/out memory reference (buffer), then the TA should implemented the following
311sequence:
312
313.. code-block:: c
314
315 TEE_Result handle_command_0(void *session, uint32_t cmd_id,
316 uint32_t param_types, TEE_Param params[4])
317 {
318 if ((TEE_PARAM_TYPE_GET(param_types, 0) != TEE_PARAM_TYPE_VALUE_IN) ||
319 (TEE_PARAM_TYPE_GET(param_types, 1) != TEE_PARAM_TYPE_VALUE_OUT) ||
320 (TEE_PARAM_TYPE_GET(param_types, 2) != TEE_PARAM_TYPE_MEMREF_INOUT) ||
321 (TEE_PARAM_TYPE_GET(param_types, 3) != TEE_PARAM_TYPE_NONE)) {
322 return TEE_ERROR_BAD_PARAMETERS
323 }
324
325 /* process command */
326 ...
327 }
328
329 TEE_Result TA_InvokeCommandEntryPoint(void *session, uint32_t command_id,
330 uint32_t param_types, TEE_Param params[4])
331 {
332 switch (command_id) {
333 case 0:
334 return handle_command_0(session, param_types, params);
335
336 default:
337 return TEE_ERROR_NOT_SUPPORTED;
338 }
339 }
Markus S. Wamser1aa72d82019-02-28 15:21:08 +0100340
341.. _TASign:
342
343Signing of TAs
344**************
345
346All :ref:`REE Filesystem Trusted Applications<ree_fs_ta>` need to be signed. The
347signature is verified by :ref:`optee_os` upon loading of the TA. Within the
348:ref:`optee_os` source is a directory ``keys``. The public part of
349``keys/default_ta.pem`` will be compiled into the :ref:`optee_os` binary and the
350signature of each TA will be verified against this key upon loading. Currently
351``keys/default_ta.pem`` must contain an RSA key.
352
353.. warning::
354
355 :ref:`optee_os` comes with a default **private** key in its source to
356 facilitate easy development, testing, debugging and QA. Never deploy an
357 :ref:`optee_os` binary with this key in production. Instead replace this key
358 as soon as possible with a public key and keep the private part of the key
359 offline, preferably on an HSM.
360
361.. note::
362
363 Currently only a single key for signing TAs is supported by :ref:`optee_os`.
364
365TAs are signed using the ``sign.py`` script referenced from
366``ta/mk/ta_dev_kit.mk`` in :ref:`optee_os`. Its default behaviour is to sign a
367compiled TA binary and attach the signature to form a complete TA for
368deployment. For **offline** signing, a three-step process is required: In a
369first step a digest of the compiled binary has to be generated, in the second
370step this digest is signed offline using the private key and finally in the
371third step the binary and its signature are stitched together into the full TA.
372
373Offline Signing of TAs
374======================
375
376The TA dev kit does sign an application as last step of the linking process. For
377example, the file ``ta/arch/arm/link.mk`` in the :ref:`optee_os` source tree
378contains the statement
379
380.. code-block:: sh
381
382 $(q)$(SIGN) --key $(TA_SIGN_KEY) --uuid $(user-ta-uuid) \
383 --in $$< --out $$@
384
385To avoid build errors when signing offline, this make script needs to be
386adopted. The signing script can be found at
387``$(TA_DEV_KIT_DIR)/../scripts/sign.py``
388
389Overall, offline signing is done with the following sequence of steps:
390
3910. (Preparation) Generate a 2048 bit RSA key for signing in a secure, offline
392environment. Extract the public key and copy it to the ``keys`` directory in the
393:ref:`optee_os` source tree. Adjust ``TA_SIGN_KEY`` for different file/path
394names. (Copy and) modify the ``link.mk`` file for the default linking step to
395produce a digest of the TA binary instead of the full TA.
396
3971. Manually (or with the modified linking script) generate a digest of the TA
398binary using
399
400.. code-block:: sh
401
402 sign.py digest --key $(TA_SIGN_KEY) --uuid $(user-ta-uuid)
403
4042. Sign this digest offline, e.g. with OpenSSL
405
406.. code-block:: sh
407
408 base64 --decode digestfile | \
409 openssl pkeyutl -sign -inkey $TA_SIGN_KEY \
410 -pkeyopt digest:sha256 -pkeyopt rsa_padding_mode:pkcs1 | \
411 base64 > sigfile
412
413or with pkcs11-tool using a Nitrokey HSM
414
415.. code-block:: sh
416
417 echo "0000: 3031300D 06096086 48016503 04020105 000420" | \
418 xxd -c 19 -r > /tmp/sighdr
419 cat /tmp/sighdr $(base64 --decode digestfile) > /tmp/hashtosign
420 pkcs11-tool --id $key_id -s --login -m RSA-PKCS \
421 --input-file /tmp/hashtosign | \
422 base64 > sigfile
423
4243. Manually (or with an extra make target) stitch the TA together using
425
426.. code-block:: sh
427
428 sign.py stitch --key $(TA_SIGN_KEY) --uuid $(user-ta-uuid)
429
430By default the UUID is taken as the base file name for all files. Different file
431names and paths can be set through additional options to ``sign.py``. Consult
432``sign.py --help`` for a full list of options and parameters.