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