xref: /xnu-8796.141.3/EXTERNAL_HEADERS/img4/firmware.h (revision 1b191cb58250d0705d8a51287127505aa4bc0789)
1 /*!
2  * @header
3  * Interfaces for manipulating Image4 firmware objects.
4  */
5 #ifndef __IMG4_FIRMWARE_H
6 #define __IMG4_FIRMWARE_H
7 
8 #define __IMG4_INDIRECT 1
9 #include <img4/api.h>
10 
11 /*!
12  * @discussion
13  * When used from the pmap layer, this header pulls in the types from libsa,
14  * which conflict with the BSD sys/types.h header that we need to pull in. But
15  * we only need it for the errno_t typedef and the vnode_t typedef. So when
16  * building MACH_KERNEL_PRIVATE, we do two things:
17  *
18  *     1. Explicitly pull in <sys/_types/_errno_t.h>, so we get errno_t and
19  *        nothing else (no transitive #include's)
20  *     2. #define _SYS_TYPES_H_ before #includ'ing <sys/kernel_types.h> so that
21  *        we don't get the transitive #include of <sys/types.h> but we still get
22  *        the definitions we need
23  */
24 #if IMG4_TARGET_XNU
25 #if MACH_KERNEL_PRIVATE
26 #define _SYS_TYPES_H_ 1
27 #include <sys/kernel_types.h>
28 #include <sys/_types/_errno_t.h>
29 #else
30 #include <sys/kernel_types.h>
31 #include <sys/types.h>
32 #endif
33 
34 #if XNU_KERNEL_PRIVATE
35 #include <img4/4xnu.h>
36 #endif
37 #endif // IMG4_TARGET_XNU
38 
39 #if IMG4_TARGET_DARWIN
40 #include <os/stdio.h>
41 #include <sys/types.h>
42 #include <img4/4ignition.h>
43 #include <img4/4MSU.h>
44 #endif
45 
46 __BEGIN_DECLS
47 OS_ASSUME_NONNULL_BEGIN
48 
49 /*!
50  * @typedef img4_4cc_t
51  * A type which represents a four-character code (4cc) that identifies the
52  * firmware. These 4cc's are statically assigned and correspond to long-form tag
53  * names -- e.g. the 4cc 'krnl' corresponds to the "KernelCache" tag.
54  */
55 IMG4_API_AVAILABLE_20200508
56 typedef uint32_t img4_4cc_t;
57 
58 /*!
59  * @typedef img4_buff_t
60  * A structure describing a buffer. See {@link _img4_buff}.
61  */
62 IMG4_API_AVAILABLE_20200508
63 typedef struct _img4_buff img4_buff_t;
64 
65 /*!
66  * @const IMG4_DGST_STRUCT_VERSION
67  * The version of the {@link img4_dgst_t} structure supported by the
68  * implementation.
69  */
70 #define IMG4_DGST_STRUCT_VERSION (0u)
71 
72 /*!
73  * @const IMG4_DGST_MAX_LEN
74  * The maximum length of a digest representable by an {@link img4_dgst_t}.
75  */
76 #define IMG4_DGST_MAX_LEN (48u)
77 
78 /*!
79  * @typedef img4_dgst_t
80  * A type representing an Image4 identifier which is a digest.
81  *
82  * @field i4d_len
83  * The version of the structure. Initialize to {@link IMG4_DGST_STRUCT_VERSION}.
84  *
85  * @field i4d_len
86  * The length of the digest.
87  *
88  * @field i4d_bytes
89  * The digest bytes.
90  */
91 IMG4_API_AVAILABLE_20200508
92 typedef struct _img4_dgst {
93 	img4_struct_version_t i4d_version;
94 	size_t i4d_len;
95 	uint8_t i4d_bytes[IMG4_DGST_MAX_LEN];
96 } img4_dgst_t;
97 
98 /*!
99  * @const IMG4_DGST_INIT
100  * A convenience initializer for an {@link img4_dgst_t} structure.
101  */
102 #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
103 #define IMG4_DGST_INIT (img4_dgst_t){ \
104 	.i4d_version = IMG4_DGST_STRUCT_VERSION, \
105 	.i4d_len = 0, \
106 	.i4d_bytes = {0}, \
107 }
108 #elif defined(__cplusplus) && __cplusplus >= 201103L
109 #define IMG4_DGST_INIT (img4_dgst_t{ \
110 	IMG4_DGST_STRUCT_VERSION, \
111 	0, \
112 	{0}, \
113 })
114 #elif defined(__cplusplus)
115 #define IMG4_DGST_INIT (img4_nonce_t((img4_nonce_t){ \
116 	IMG4_DGST_STRUCT_VERSION, \
117 	0, \
118 	{0}, \
119 }))
120 #else
121 #define IMG4_DGST_INIT {IMG4_DGST_STRUCT_VERSION}
122 #endif
123 
124 /*!
125  * @struct _img4_cstr
126  * A type representing an Image4 identifier which is a C-string. These
127  * identifiers can be no more than 64 bytes in length, including the null
128  * terminating byte.
129  *
130  * @field i4b_len
131  * The length of the C-string, not including the null terminating byte.
132  *
133  * @field i4b_cstr
134  * The null-terminated C-string.
135  *
136  * @discussion
137  * This structure is intentionally unversioned. It should never evolve into
138  * anything more complex than it is.
139  */
140 IMG4_API_AVAILABLE_20210113
141 typedef struct _img4_cstr {
142 	size_t i4cs_len;
143 	char i4cs_cstr[64];
144 } img4_cstr_t;
145 
146 /*!
147  * @const IMG4_CSTR_INIT
148  * A convenience initializer for an {@link img4_cstr_t}.
149  */
150 #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
151 #define IMG4_CSTR_INIT (img4_cstr_t){ \
152 	.i4cs_len = 0, \
153 	.i4cs_cstr = {0}, \
154 }
155 #elif defined(__cplusplus) && __cplusplus >= 201103L
156 #define IMG4_CSTR_INIT (img4_cstr_t{ \
157 	0, \
158 	{0}, \
159 })
160 #elif defined(__cplusplus)
161 #define IMG4_CSTR_INIT \
162 		(img4_cstr_t((img4_cstr_t){ \
163 	0, \
164 	{0}, \
165 }))
166 #else
167 #define IMG4_CSTR_INIT {0}
168 #endif
169 
170 /*!
171  * @typedef img4_chip_t
172  * An opaque type describing a destination chip environment for the firmware
173  * image.
174  */
175 IMG4_API_AVAILABLE_20200508
176 typedef struct _img4_chip img4_chip_t;
177 
178 /*!
179  * @typedef img4_firmware_t
180  * An opaque type describing an Image4 firmware object.
181  */
182 IMG4_API_AVAILABLE_20200508
183 typedef struct _img4_firmware *img4_firmware_t;
184 
185 /*!
186  * @typedef img4_image_t
187  * An opaque type describing an authenticated Image4 firmware image.
188  */
189 IMG4_API_AVAILABLE_20200508
190 typedef struct _img4_image *img4_image_t;
191 
192 /*!
193  * @typedef img4_runtime_t
194  * A structure describing required primitives in the operating environment's
195  * runtime. See {@link _img4_runtime}.
196  */
197 IMG4_API_AVAILABLE_20200508
198 typedef struct _img4_runtime img4_runtime_t;
199 
200 OS_ASSUME_NONNULL_END
201 
202 #include <img4/nonce.h>
203 #include <img4/object.h>
204 #include <img4/chip.h>
205 #include <img4/chip_ap.h>
206 #include <img4/chip_ap_category.h>
207 #include <img4/chip_ap_software.h>
208 #include <img4/chip_cryptex1.h>
209 #include <img4/chip_sep.h>
210 #include <img4/chip_x86.h>
211 #include <img4/image.h>
212 #include <img4/runtime.h>
213 
214 OS_ASSUME_NONNULL_BEGIN
215 
216 /*!
217  * @typedef img4_firmware_authenticated_execute_t
218  * A firmware execution function. This function is called when the firmware has
219  * been successfully authenticated and is ready for execution.
220  *
221  * @param fw
222  * The firmware which has been authenticated.
223  *
224  * @param image
225  * The resulting firmware image that may be executed. The implementation will
226  * pass NULL if there was a failure.
227  *
228  * This object is automatically freed by the implementation upon return.
229  *
230  * @param error
231  * An error code describing the result of the authentication. If authentication
232  * was successful, the implementation will pass zero. Otherwise, one of the
233  * following error codes will be provided:
234  *
235  *     [EILSEQ]     The firmware data is not valid Image4 data -- this will not
236  *                  be passed for firmwares created with
237  *                  {@link IMG4_FIRMWARE_FLAG_BARE}
238  *     [EFTYPE]     The attached manifest is not a valid Image4 manifest
239  *     [ENOENT]     The attached manifest does not authenticate this type of
240  *                  firmware
241  *     [EAUTH]      The attached manifest is not authentic (i.e. was not signed
242  *                  by an Apple CA)
243  *     [EACCES]     The given chip does not satisfy the constraints of the
244  *                  attached manifest
245  *     [ESTALE]     The manifest has been invalidated and is no longer valid for
246  *                  the provided chip
247  *     [ENOEXEC]    The firmware has been corrupted, or the given chip does not
248  *                  satisfy the constraints of the corresponding object in the
249  *                  attached manifest
250  *
251  * @param _ctx
252  * The user-provided context pointer.
253  */
254 IMG4_API_AVAILABLE_20200508
255 typedef void (*img4_firmware_authenticated_execute_t)(
256 	const img4_firmware_t fw,
257 	img4_image_t _Nullable image,
258 	errno_t error,
259 	void *_ctx
260 );
261 
262 #if IMG4_TARGET_EFI
263 typedef void (*img4_firmware_authenticated_execute_efi_t)(
264 	const img4_firmware_t fw,
265 	img4_image_t _Nullable image,
266 	EFI_STATUS status,
267 	void *_ctx
268 );
269 #endif
270 
271 /*!
272  * @define IMG4_FIRMWARE_EXECUTION_CONTEXT_STRUCT_VERSION
273  * The version of the {@link img4_firmware_execution_context_t} structure
274  * supported by the implementation.
275  */
276 #define IMG4_FIRMWARE_EXECUTION_CONTEXT_STRUCT_VERSION (1u)
277 
278 /*!
279  * @typedef img4_firmware_execution_context_t
280  * A structure describing the context in which a firmware is to be executed.
281  *
282  * @field i4fex_version
283  * The version of the structure supported by the implementation. Initialize to
284  * {@link IMG4_FIRMWARE_EXECUTION_CONTEXT_STRUCT_VERSION}.
285  *
286  * @field i4fex_execute
287  * A pointer to the firmware execution function.
288  *
289  * @field i4fex_execute_efi
290  * A pointer to the EFI-specific firmware execution function. This is only
291  * available in the EFI environment. If both this field and
292  * {@link i4fex_execute} are specified in the execution context, the
293  * one which is called by the implementation will be undefined.
294  *
295  * This field was added in version 1 of the structure. It was not appended to
296  * the end of the structure since the non-EFI structure did not change, and the
297  * structure did not previously exist in the EFI environment. The version
298  * increment was not strictly necessary, but was done for hygienic reasons.
299  *
300  * @field i4fex_context
301  * A caller-provided context pointer that will be passed to functions invoked
302  * from the execution context.
303  */
304 IMG4_API_AVAILABLE_20200508
305 typedef struct _img4_firmware_execution_context {
306 	img4_struct_version_t i4fex_version;
307 	img4_firmware_authenticated_execute_t i4fex_execute;
308 #if IMG4_TARGET_EFI
309 	img4_firmware_authenticated_execute_efi_t i4fex_execute_efi;
310 #endif
311 	void *i4fex_context;
312 } img4_firmware_execution_context_t;
313 
314 /*!
315  * @typedef img4_firmware_flags_t
316  * A bitfield modifying the behavior of an {@link img4_firmware_t} object.
317  *
318  * @const IMG4_FIRMWARE_FLAG_INIT
319  * No bits set. This value is suitable for initialization purposes.
320  *
321  * @const IMG4_FIRMWARE_FLAG_ATTACHED_MANIFEST
322  * The manifest authenticating the firmware is attached (i.e. the buffer given
323  * represents a .img4 file).
324  *
325  * @const IMG4_FIRMWARE_FLAG_BARE
326  * The firmware image is not wrapped with an Image4 payload structure. This flag
327  * is mutually exclusive with {@link IMG4_FIRMWARE_FLAG_ATTACHED_MANIFEST}, and
328  * if both are present, the implementation's behavior is undefined.
329  *
330  * @const IMG4_FIRMWARE_FLAG_SUBSEQUENT_STAGE
331  * The firmware image extends an existing chain of trust. If set, the
332  * runtime must provide a {@link i4rt_get_digest} function which returns a
333  * digest for {@link IMG4_IDENTIFIER_CHMH}.
334  *
335  * If set, the firmware may optionally provide a {@link i4rt_get_bool} function
336  * which returns a value for {@link IMG4_IDENTIFIER_AMNM}.
337  *
338  * @const IMG4_FIRMWARE_FLAG_RESPECT_AMNM
339  * Forces the implementation to respect the manifest's AMNM entitlement if it is
340  * present, even if the validation is creating a new chain of trust. This is
341  * technically maybe sort of against the Image4 spec, but it is useful for
342  * certain internal workflows (cf. v2.3, §2.2.10).
343  *
344  * This flag has no effect if {@link IMG4_FIRMWARE_FLAG_SUBSEQUENT_STAGE} is
345  * also passed.
346  *
347  * @const IMG4_FIRMWARE_FLAG_PASSTHROUGH
348  * Causes the wrapped payload bytes to be delivered to the image execution
349  * callback. These bytes do not have the Image4 wrapping stripped.
350  *
351  * @const IMG4_FIRMWARE_FLAG_FORCE_ANTI_REPLAY
352  * Force anti-replay enforcement even when performing just manifest evaluation
353  * without executing a firmware. When executing a firmware, this flag need not
354  * be passed in since anti-replay enforcement is always enabled.
355  */
356 IMG4_API_AVAILABLE_20200508
357 OS_CLOSED_OPTIONS(img4_firmware_flags, uint64_t,
358 	IMG4_FIRMWARE_FLAG_INIT,
359 	IMG4_FIRMWARE_FLAG_ATTACHED_MANIFEST = (1 << 0),
360 	IMG4_FIRMWARE_FLAG_BARE = (1 << 1),
361 	IMG4_FIRMWARE_FLAG_SUBSEQUENT_STAGE = (1 << 2),
362 	IMG4_FIRMWARE_FLAG_RESPECT_AMNM = (1 << 3),
363 	IMG4_FIRMWARE_FLAG_PASSTHROUGH = (1 << 4),
364 	IMG4_FIRMWARE_FLAG_FORCE_ANTI_REPLAY = (1 << 5),
365 );
366 
367 /*!
368  * @function img4_firmware_new
369  * Allocate and initialize a new firmware object.
370  *
371  * @param rt
372  * The runtime in which to initialize the object.
373  *
374  * @param _4cc
375  * The 4cc which distinguishes the firmware.
376  *
377  * @param buff
378  * A buffer containing a valid Image4 payload (usually the contents of either a
379  * .im4p or .img4 file).
380  *
381  * Upon return, the destructor in the buffer is replaced with NULL, and the
382  * implementation assumes responsibility for deallocating the underlying memory.
383  *
384  * @param flags
385  * Flags modifying the behavior of the object.
386  *
387  * @result
388  * A new firmware object or NULL if there was an allocation failure. If
389  * {@link rt} has a NULL allocation function, NULL is returned.
390  *
391  * @discussion
392  * The resulting object assumes ownership of the given buffer.
393  *
394  * In the Darwin userspace runtime, NULL will not be returned.
395  */
396 #if !XNU_KERNEL_PRIVATE
397 IMG4_API_AVAILABLE_20200508
398 OS_EXPORT OS_WARN_RESULT OS_MALLOC OS_NONNULL1 OS_NONNULL2 OS_NONNULL4
399 img4_firmware_t _Nullable
400 img4_firmware_new(const img4_runtime_t *rt,
401 		const img4_firmware_execution_context_t *exec,
402 		img4_4cc_t _4cc,
403 		img4_buff_t *buff,
404 		img4_firmware_flags_t flags);
405 #else
406 #define img4_firmware_new(...) (img4if->i4if_v7.firmware_new(__VA_ARGS__))
407 #endif
408 
409 /*!
410  * @function img4_firmware_new_from_vnode_4xnu
411  * Allocate and initialize a new firmware object from a vnode.
412  *
413  * @param rt
414  * The runtime in which to initialize the object. This interface is only
415  * supported with the Darwin kernel runtime. If any other runtime is provided,
416  * the implementation's behavior is undefined.
417  *
418  * @param _4cc
419  * The 4cc which distinguishes the firmware.
420  *
421  * @param vn
422  * A vnode representing a valid Image4 payload (usually the contents of either a
423  * .im4p or .img4 file).
424  *
425  * @param flags
426  * Flags modifying the behavior of the object.
427  *
428  * @result
429  * A new firmware object or NULL if there was an allocation failure.
430  *
431  * @discussion
432  * Verification of a vnode is performed by reading in chunks of data, updating
433  * an ongoing hash operation with that data, and then discarding it. Therefore,
434  * firmware objects created in this manner can only guarantee their validity at
435  * the time the check was performed since the vnode's contents are not kept in
436  * memory and may be tampered with after validation has been performed.
437  *
438  * As such, on successful execution, the image passed to the
439  * {@link img4_firmware_authenticated_execute_t} function of the execution
440  * context is NULL.
441  *
442  * Firmwares created with this interface cannot be created with the
443  * {@link IMG4_FIRMWARE_FLAG_ATTACHED_MANIFEST} flag.
444  */
445 #if IMG4_TARGET_XNU
446 #if !XNU_KERNEL_PRIVATE
447 IMG4_API_AVAILABLE_20200508
448 OS_EXPORT OS_WARN_RESULT OS_MALLOC OS_NONNULL1 OS_NONNULL2 OS_NONNULL4
449 img4_firmware_t _Nullable
450 img4_firmware_new_from_vnode_4xnu(const img4_runtime_t *rt,
451 		const img4_firmware_execution_context_t *exec,
452 		img4_4cc_t _4cc,
453 		vnode_t vn,
454 		img4_firmware_flags_t flags);
455 #else
456 #define img4_firmware_new_from_vnode_4xnu(...) \
457 		(img4if->i4if_v7.firmware_new_from_vnode_4xnu(__VA_ARGS__))
458 #endif // !XNU_KERNEL_PRIVATE
459 #endif // IMG4_TARGET_XNU
460 
461 /*!
462  * @function img4_firmware_new_from_fd_4MSM
463  * Allocate and initialize a new firmware object from a file descriptor.
464  *
465  * @param rt
466  * The runtime in which to initialize the object. This interface is only
467  * supported with the Darwin userspace runtime. If any other runtime is
468  * provided, the implementation's behavior is undefined.
469  *
470  * @param _4cc
471  * The 4cc which distinguishes the firmware.
472  *
473  * @param fd
474  * A pointer to a file descriptor representing a valid Image4 payload (usually
475  * the contents of either a .im4p or .img4 file). The object assumes ownership
476  * of the descriptor, and upon return, the value referenced by the pointer will
477  * be set to -1.
478  *
479  * @param flags
480  * Flags modifying the behavior of the object.
481  *
482  * @result
483  * A new firmware object. The implementation will not return NULL.
484  *
485  * @discussion
486  * This interface is the userspace equivalent of
487  * {@link img4_firmware_new_from_vnode_4xnu}, and all the same caveats apply.
488  */
489 #if IMG4_TARGET_DARWIN
490 IMG4_API_AVAILABLE_20200508
491 OS_EXPORT OS_WARN_RESULT OS_MALLOC OS_NONNULL1 OS_NONNULL2
492 img4_firmware_t
493 img4_firmware_new_from_fd_4MSM(const img4_runtime_t *rt,
494 		const img4_firmware_execution_context_t *exec,
495 		img4_4cc_t _4cc,
496 		os_fd_t *fd,
497 		img4_firmware_flags_t flags);
498 #endif
499 
500 /*!
501  * @function img4_firmware_init_from_buff
502  * Initializes a buffer as a firmware object. This interface is useful for
503  * runtimes which do not provide for dynamic memory allocation.
504  *
505  * @param storage
506  * A pointer to the storage to use for the firmware object.
507  *
508  * @param len
509  * The size of the buffer.
510  *
511  * @discussion
512  * The caller is expected to pass a buffer that is "big enough". If the provided
513  * buffer is too small, the implementation will abort the caller.
514  *
515  * @example
516  *
517  *     uint8_t _buff[IMG4_FIRMWARE_SIZE_RECOMMENDED];
518  *     img4_firmware_t fw = NULL;
519  *
520  *     fw = img4_firmware_init_from_buff(_buff, sizeof(_buff));
521  *     img4_firmware_init(fw, IMG4_RUNTIME_DEFAULT, &exec_context,
522  *             kImg4Tag_krnl, fw_buff, 0);
523  */
524 #if !XNU_KERNEL_PRIVATE
525 IMG4_API_AVAILABLE_20200508
526 OS_EXPORT OS_WARN_RESULT OS_NONNULL1
527 img4_firmware_t
528 img4_firmware_init_from_buff(void *buff, size_t len);
529 #else
530 #define img4_firmware_init_from_buff(...) \
531 		(img4if->i4if_v7.firmware_init_from_buff(__VA_ARGS__))
532 #endif
533 
534 /*!
535  * @function img4_firmware_init
536  * Initialize a firmware object.
537  *
538  * @param fw
539  * A pointer to the storage for the firmware object. This pointer should refer
540  * to a region of memory that is sufficient to hold a {@link img4_firmware_t}
541  * object. This size should be queried with the {@link i4rt_object_size}
542  * function of the runtime.
543  *
544  * @param rt
545  * The runtime in which to initialize the object.
546  *
547  * @param _4cc
548  * The 4cc which distinguishes the firmware.
549  *
550  * @param buff
551  * A buffer containing a valid Image4 payload (usually the contents of either a
552  * .im4p or .img4 file).
553  *
554  * Upon return, the destructor in the buffer is replaced with NULL, and the
555  * implementation assumes responsibility for deallocating the underlying memory.
556  *
557  * @param flags
558  * Flags modifying the behavior of the object.
559  *
560  * @discussion
561  * The resulting object assumes ownership of the given buffer. This routine
562  * should only be used when dynamic memory allocation is not available in the
563  * runtime. Otherwise, use {@link img4_firmware_new}.
564  */
565 #if !XNU_KERNEL_PRIVATE
566 IMG4_API_AVAILABLE_20200508
567 OS_EXPORT OS_NONNULL1 OS_NONNULL2 OS_NONNULL3 OS_NONNULL5
568 void
569 img4_firmware_init(img4_firmware_t fw,
570 		const img4_runtime_t *rt,
571 		const img4_firmware_execution_context_t *exec,
572 		img4_4cc_t _4cc,
573 		img4_buff_t *buff,
574 		img4_firmware_flags_t flags);
575 #else
576 #define img4_firmware_init(...) (img4if->i4if_v7.firmware_init(__VA_ARGS__))
577 #endif
578 
579 /*!
580  * @function img4_firmware_init_sentinel
581  * Initialize a firmware object as a sentinel without any manifest attached.
582  * This firmware has no object tag and is not executable. It is only suitable
583  * for use with {@link img4_firmware_attach_manifest} and
584  * {@link img4_firmware_evaluate} to determine whether a manifest is acceptable
585  * to a particular chip environment.
586  *
587  * @param fw
588  * A pointer to the storage for the firmware object. This pointer should refer
589  * to a region of memory that is sufficient to hold a {@link img4_firmware_t}
590  * object. This size should be queried with the {@link i4rt_object_size}
591  * function of the runtime.
592  *
593  * @param rt
594  * The runtime in which to initialize the object.
595  *
596  * @param flags
597  * Flags modifying the behavior of the object.
598  *
599  * @discussion
600  * Sentinel firmwares do not enforce anti-replay, so
601  * {@link img4_firmware_evaluate} will not return ESTALE when evaluating such
602  * firmwares. Anti-replay enforcement can be enabled by using
603  * {@link IMG4_FIRMWARE_FLAG_FORCE_ANTI_REPLAY}.
604  */
605 #if !XNU_KERNEL_PRIVATE
606 IMG4_API_AVAILABLE_20211126
607 OS_EXPORT OS_NONNULL1 OS_NONNULL2
608 void
609 img4_firmware_init_sentinel(img4_firmware_t fw,
610 		const img4_runtime_t *rt,
611 		img4_firmware_flags_t flags);
612 #else
613 #define img4_firmware_init_sentinel(...) \
614 		(img4if->i4if_v17.firmware_init_sentinel(__VA_ARGS__))
615 #endif
616 
617 /*!
618  * @function img4_firmware_attach_manifest
619  * Attaches a signed manifest to the firmware.
620  *
621  * @param fw
622  * The firmware to manipulate.
623  *
624  * @param buff
625  * A buffer containing a valid Image4 manifest (usually the contents of either a
626  * .im4m or .img4 file).
627  *
628  * Upon return, the destructor in the buffer is replaced with NULL, and the
629  * implementation assumes responsibility for deallocating the underlying memory.
630  *
631  * @discussion
632  * If this interface is called on a firmware created with the
633  * {@link IMG4_FIRMWARE_FLAG_ATTACHED_MANIFEST} flag, the implementation's
634  * behavior is undefined.
635  *
636  * This interface must be called on any firmware created with the
637  * {@link IMG4_FIRMWARE_FLAG_BARE} flag.
638  *
639  * The object assumes ownership of the given buffer.
640  */
641 #if !XNU_KERNEL_PRIVATE
642 IMG4_API_AVAILABLE_20200508
643 OS_EXPORT OS_NONNULL1 OS_NONNULL2
644 void
645 img4_firmware_attach_manifest(img4_firmware_t fw,
646 		img4_buff_t *buff);
647 #else
648 #define img4_firmware_attach_manifest(...) \
649 		(img4if->i4if_v7.firmware_attach_manifest(__VA_ARGS__))
650 #endif
651 
652 /*!
653  * @function img4_firmware_select_chip
654  * Returns the chip from the provided array which may be used to authenticate
655  * the firmware.
656  *
657  * @param fw
658  * The firmware to query.
659  *
660  * @param acceptable_chips
661  * An array of chips the caller finds acceptable to verify the firmware.
662  *
663  * @param acceptable_chips_cnt
664  * The number of elements in {@link acceptable_chips}.
665  *
666  * @result
667  * If the manifest may be authenticated by the certificate chain associated with
668  * one of the manifests provided in {@link acceptable_chips}, that chip is
669  * returned. If the manifest cannot be authenticated with any of the provided
670  * chips, NULL is returned.
671  *
672  * @discussion
673  * The result of calling this function on a firmware which does not have a
674  * manifest attached is undefined.
675  *
676  * If multiple chips may be used to authenticate the firmware, the
677  * implementation does not define which of those chips will be returned.
678  *
679  * If the firmware was created without the
680  * {@link IMG4_FIRMWARE_FLAG_SUBSEQUENT_STAGE} flag, this function will return
681  * NULL. This function cannot be used to establish new trust chains, only to
682  * verify an existing one.
683  */
684 #if !XNU_KERNEL_PRIVATE
685 IMG4_API_AVAILABLE_20200724
686 OS_EXPORT OS_WARN_RESULT
687 const img4_chip_t *_Nullable
688 img4_firmware_select_chip(const img4_firmware_t fw,
689 		const img4_chip_select_array_t _Nonnull acceptable_chips,
690 		size_t acceptable_chips_cnt);
691 #else
692 #define img4_firmware_select_chip(...) \
693 		(img4if->i4if_v10.firmware_select_chip(__VA_ARGS__))
694 #endif
695 
696 /*!
697  * @function img4_firmware_execute
698  * Authenticate the firmware and execute it within its context.
699  *
700  * @param fw
701  * The firmware to execute.
702  *
703  * @param chip
704  * The chip on which to execute the firmware.
705  *
706  * @param nonce
707  * The nonce to use for authentication. May be NULL if the chip environment does
708  * not maintain an anti-replay token or if a chained evaluation is being
709  * performed.
710  *
711  * @discussion
712  * The implementation will always invoke the
713  * {@link img4_firmware_authenticated_execute_t} provided in the execution
714  * context with either a successful result or a failure. All error handling must
715  * take place in that context.
716  *
717  * The {@link img4_firmware_authenticated_execute_t} is called before the
718  * implementation returns.
719  *
720  * The result of executing a firmware without a manifest attached (either via
721  * {@link img4_firmware_attach_manifest} or by creating the firmware with the
722  * {@link IMG4_FIRMWARE_FLAG_ATTACHED_MANIFEST} flag set) is undefined.
723  */
724 #if !XNU_KERNEL_PRIVATE
725 IMG4_API_AVAILABLE_20200508
726 OS_EXPORT OS_NONNULL1 OS_NONNULL2
727 void
728 img4_firmware_execute(img4_firmware_t fw,
729 		const img4_chip_t *chip,
730 		const img4_nonce_t *_Nullable nonce);
731 #else
732 #define img4_firmware_execute(...) \
733 		(img4if->i4if_v7.firmware_execute(__VA_ARGS__))
734 #endif
735 
736 /*!
737  * @function img4_firmware_evaluate
738  * Evaluate the firmware for authenticity.
739  *
740  * @param fw
741  * The firmware to evaluate.
742  *
743  * @param chip
744  * The chip on which to evaluate the firmware.
745  *
746  * @param nonce
747  * The nonce to use for authentication. May be NULL if the chip environment does
748  * not maintain an anti-replay token or if a chained evaluation is being
749  * performed.
750  *
751  * @result
752  * An error code describing the result of the authentication. If authentication
753  * was successful, zero is returned. Otherwise, one of the following error codes
754  * will be returned:
755  *
756  *     [EILSEQ]     The firmware data is not valid Image4 data -- this will not
757  *                  be returned for firmwares created with
758  *                  {@link IMG4_FIRMWARE_FLAG_BARE}
759  *     [EFTYPE]     The attached manifest is not a valid Image4 manifest
760  *     [ENOENT]     The attached manifest does not authenticate this type of
761  *                  firmware
762  *     [EAUTH]      The attached manifest is not authentic (i.e. was not signed
763  *                  by an Apple CA)
764  *     [EACCES]     The given chip does not satisfy the constraints of the
765  *                  attached manifest
766  *     [ESTALE]     The manifest has been invalidated and is no longer valid for
767  *                  the provided chip
768  *     [ENOEXEC]    The firmware has been corrupted, or the given chip does not
769  *                  satisfy the constraints of the corresponding object in the
770  *                  attached manifest
771  *     [EPWROFF]    The chip environment has not yet booted; most chip
772  *                  environments are booted and available by the time the caller
773  *                  has begun executing, but some require additional
774  *                  initialization before they can execute objects
775  *
776  * @discussion
777  * This interface should be used when the caller is only concerned with the
778  * authenticity and integrity of the firmware image and does not intend to
779  * execute it.
780  *
781  * The result of evaluating a firmware without a manifest attached (either via
782  * {@link img4_firmware_attach_manifest} or by creating the firmware with the
783  * {@link IMG4_FIRMWARE_FLAG_ATTACHED_MANIFEST} flag set) is undefined.
784  */
785 #if !XNU_KERNEL_PRIVATE
786 IMG4_API_AVAILABLE_20200608
787 OS_EXPORT OS_WARN_RESULT OS_NONNULL1 OS_NONNULL2
788 errno_t
789 img4_firmware_evaluate(img4_firmware_t fw,
790 		const img4_chip_t *chip,
791 		const img4_nonce_t *_Nullable nonce);
792 #else
793 #define img4_firmware_evaluate(...) \
794 		(img4if->i4if_v9.firmware_evaluate(__VA_ARGS__))
795 #endif
796 
797 /*!
798  * @function img4_firmware_destroy
799  * Destroys a firmware object and releases the associated resources according to
800  * the runtime's specification.
801  *
802  * @param fw
803  * A pointer to the firmware object.
804  *
805  * Upon return, this will be replaced with a known-invalid pointer value. This
806  * parameter may be NULL in which case the implementation will return
807  * immediately.
808  *
809  * @discussion
810  * The implementation will invoke the provided deallocation function of the
811  * buffer object underlying the firmware.
812  */
813 #if !XNU_KERNEL_PRIVATE
814 IMG4_API_AVAILABLE_20200508
815 OS_EXPORT
816 void
817 img4_firmware_destroy(img4_firmware_t _Nonnull *_Nullable fw);
818 #else
819 #define img4_firmware_destroy(...) \
820 		(img4if->i4if_v7.firmware_destroy(__VA_ARGS__))
821 #endif
822 
823 OS_ASSUME_NONNULL_END
824 __END_DECLS
825 
826 #endif // __IMG4_FIRMWARE_H
827