1/*!
2 * @header
3 * Encapsulation which describes an Image4 environment. The environment
4 * encompasses chip properties and trust evaluation policies, including digest
5 * algorithm selection and secure boot level enforcement.
6 */
7#ifndef __IMAGE4_API_ENVIRONMENT_H
8#define __IMAGE4_API_ENVIRONMENT_H
9
10#include <image4/image4.h>
11#include <image4/types.h>
12#include <image4/coprocessor.h>
13#include <stdbool.h>
14
15__BEGIN_DECLS
16OS_ASSUME_NONNULL_BEGIN
17OS_ASSUME_PTR_ABI_SINGLE_BEGIN
18
19#pragma mark Forward Types
20/*!
21 * @typedef image4_environment_storage_t
22 * The canonical type for environment storage.
23 */
24typedef struct _image4_environment_storage image4_environment_storage_t;
25
26/*!
27 * @typedef image4_environment_query_boot_nonce_t
28 * A callback to provide the boot nonce for the environment.
29 *
30 * @param env
31 * The environment for which to retrieve the boot nonce.
32 *
33 * @param n
34 * Storage in which the callee should write the nonce upon successful return.
35 *
36 * @param n_len
37 * Storage in which the callee should write the nonce length upon successful
38 * return.
39 *
40 * On function entry, the content of this parameter is undefined.
41 *
42 * @param _ctx
43 * The context pointer which was provided during the environment's construction.
44 *
45 * @result
46 * The callee is expected to return zero on success. Otherwise, the callee may
47 * return one of the following POSIX error codes:
48 *
49 * [ENOTSUP] Obtaining the boot nonce is not supported; this will cause the
50 * implementation to act as if no callback was specified
51 * [ENOENT] The boot nonce does not exist
52 * [ENXIO] The boot nonce is not yet available for the environment, and
53 * the environment's bootstrap nonce (if any) should be used for
54 * anti-replay instead
55 *
56 * @discussion
57 * This callback is utilized by exec, sign, and boot trust evaluations.
58 */
59typedef errno_t (*image4_environment_query_boot_nonce_t)(
60 const image4_environment_t *env,
61 uint8_t n[__static_size _Nonnull IMAGE4_NONCE_MAX_LEN],
62 size_t *n_len,
63 void *_ctx
64);
65
66/*!
67 * @typedef image4_environment_query_nonce_digest_t
68 * A callback to provide a nonce digest for use during preflight trust
69 * evaluations.
70 *
71 * @param env
72 * The environment for which to retrieve the boot nonce.
73 *
74 * @param nd
75 * Storage in which the callee should write the nonce digest upon successful
76 * return.
77 *
78 * @param nd_len
79 * Storage in which the callee should write the nonce digest length upon
80 * successful return.
81 *
82 * On function entry, the content of this parameter is undefined.
83 *
84 * @param _ctx
85 * The context pointer which was provided during the environment's construction.
86 *
87 * @result
88 * The callee is expected to return zero on success. Otherwise, the callee may
89 * return one of the following POSIX error codes:
90 *
91 * [ENOTSUP] Obtaining the nonce digest is not supported; this will cause
92 * the implementation to act as if no callback was specified
93 * [ENOENT] The nonce digest does not exist
94 *
95 * @discussion
96 * This callback is utilized by preflight, sign, and boot trust evaluations. In
97 * sign and trust trust evaluations, it is only called if the nonce itself
98 * cannot be obtained from either the environment internally or the boot nonce
99 * callback.
100 */
101typedef errno_t (*image4_environment_query_nonce_digest_t)(
102 const image4_environment_t *env,
103 uint8_t nd[__static_size _Nonnull IMAGE4_NONCE_DIGEST_MAX_LEN],
104 size_t *nd_len,
105 void *_ctx
106);
107
108/*!
109 * @typedef image4_environment_identifier_bool_t
110 * A callback which conveys the value of a Boolean identifier associated with
111 * the environment during an identification.
112 *
113 * @param nv
114 * The environment which is being identified.
115 *
116 * @param id4
117 * The Boolean identifier.
118 *
119 * @param val
120 * The value of the identifier.
121 *
122 * @param _ctx
123 * The context pointer which was provided during the environment's construction.
124 */
125typedef void (*image4_environment_identifier_bool_t)(
126 const image4_environment_t *nv,
127 const image4_identifier_t *id4,
128 bool val,
129 void *_ctx
130);
131
132/*!
133 * @typedef image4_environment_identifier_integer_t
134 * A callback which conveys the value of an unsigned 64-bit integer identifier
135 * associated with the environment during an identification.
136 *
137 * @param nv
138 * The environment which is being identified.
139 *
140 * @param id4
141 * The integer identifier.
142 *
143 * @param val
144 * The value of the identifier.
145 *
146 * @param _ctx
147 * The context pointer which was provided during the environment's construction.
148 */
149typedef void (*image4_environment_identifier_integer_t)(
150 const image4_environment_t *nv,
151 const image4_identifier_t *id4,
152 uint64_t val,
153 void *_ctx
154);
155
156/*!
157 * @typedef image4_environment_identifier_data_t
158 * A callback which conveys the value of an octet string identifier associated
159 * with the environment during an identification.
160 *
161 * @param nv
162 * The environment which is being identified.
163 *
164 * @param id4
165 * The octet string identifier.
166 *
167 * @param vp
168 * A pointer to the octet string bytes.
169 *
170 * @param vp_len
171 * The length of the octet string indicated by {@link vp}.
172 *
173 * @param _ctx
174 * The context pointer which was provided during the environment's construction.
175 */
176typedef void (*image4_environment_identifier_data_t)(
177 const image4_environment_t *nv,
178 const image4_identifier_t *id4,
179 const void *vp,
180 size_t vp_len,
181 void *_ctx
182);
183
184/*!
185 * @const IMAGE4_ENVIRONMENT_CALLBACKS_STRUCT_VERSION
186 * The version of the {@link image4_environment_callbacks_t} structure supported
187 * by the implementation.
188 */
189#define IMAGE4_ENVIRONMENT_CALLBACKS_STRUCT_VERSION (0u)
190
191/*!
192 * @struct image4_environment_callbacks_t
193 * A callback structure which may be given to influence the behavior of an
194 * {@link image4_environment_t}.
195 *
196 * @field nvcb_version
197 * The version of the structure. Initialize to
198 * {@link IMAGE4_ENVIRONMENT_CALLBACKS_STRUCT_VERSION}.
199 *
200 * @field nvcb_query_boot_nonce
201 * The callback to query the boot nonce.
202 *
203 * @field nvcb_query_nonce_digest
204 * The callback to query a nonce digest.
205 *
206 * @field nvcb_construct_boot
207 * The callback to construct the boot sequence for the environment.
208 *
209 * @field nvcb_identifier_bool
210 * The callback to convey a Boolean identifier in the environment.
211 *
212 * @field nvcb_identifier_integer
213 * The callback to convey an integer identifier in the environment.
214 *
215 * @field nvcb_identifier_data
216 * The callback to convey an octet string identifier in the environment.
217 */
218typedef struct _image4_environment_callbacks {
219 image4_struct_version_t nvcb_version;
220 image4_environment_query_boot_nonce_t _Nullable nvcb_query_boot_nonce;
221 image4_environment_query_nonce_digest_t _Nullable nvcb_query_nonce_digest;
222 image4_environment_identifier_bool_t _Nullable nvcb_identifier_bool;
223 image4_environment_identifier_integer_t _Nullable nvcb_identifier_integer;
224 image4_environment_identifier_data_t _Nullable nvcb_identifier_data;
225} image4_environment_callbacks_t;
226
227/*!
228 * @const IMAGE4_ENVIRONMENT_STRUCT_VERSION
229 * The version of the {@link image4_environment_t} structure supported by the
230 * implementation.
231 */
232#define IMAGE4_ENVIRONMENT_STRUCT_VERSION (0u)
233
234/*!
235 * @struct image4_environment_storage_t
236 * An opaque structure which is guaranteed to be large enough to accommodate an
237 * {@link image4_environment_t}.
238 *
239 * @field __opaque
240 * The opaque storage.
241 */
242struct _image4_environment_storage {
243 uint8_t __opaque[256];
244};
245
246/*!
247 * @const IMAGE4_TRUST_STORAGE_INIT
248 * Initializer for a {@link image4_environment_storage_t} object.
249 */
250#define IMAGE4_ENVIRONMENT_STORAGE_INIT (image4_environment_storage_t){ \
251 .__opaque = { 0x00 }, \
252}
253
254#pragma mark API
255/*!
256 * @function image4_environment_init
257 * Initializes an environment in which to perform a trust evaluation.
258 *
259 * @param storage
260 * The storage structure.
261 *
262 * @param coproc
263 * The coprocessor which will perform the evaluation. If NULL,
264 * {@link IMAGE4_COPROCESSOR_HOST} will be assumed.
265 *
266 * @param handle
267 * The specific environment and policy within the coprocessor to use for
268 * performing the evaluation. If {@link IMAGE4_COPROCESSOR_HOST} is used, this
269 * parameter is ignored.
270 *
271 * @result
272 * An initialized {@link image4_environment_t} object.
273 */
274IMAGE4_API_AVAILABLE_SPRING_2024
275OS_EXPORT OS_WARN_RESULT OS_NONNULL1
276image4_environment_t *
277_image4_environment_init(
278 image4_environment_storage_t *storage,
279 const image4_coprocessor_t *_Nullable coproc,
280 image4_coprocessor_handle_t handle,
281 image4_struct_version_t v);
282#define image4_environment_init(_storage, _coproc, _handle) \
283 _image4_environment_init( \
284 (_storage), \
285 (_coproc), \
286 (_handle), \
287 IMAGE4_ENVIRONMENT_STRUCT_VERSION)
288IMAGE4_XNU_AVAILABLE_INDIRECT(_image4_environment_init);
289
290/*!
291 * @function image4_environment_new
292 * Allocates an environment in which to perform a trust evaluation.
293 *
294 * @param coproc
295 * The coprocessor which will perform the evaluation. If NULL,
296 * {@link IMAGE4_COPROCESSOR_HOST} will be assumed.
297 *
298 * @param handle
299 * The specific environment and policy within the coprocessor to use for
300 * performing the evaluation. If {@link IMAGE4_COPROCESSOR_HOST} is used, this
301 * parameter is ignored.
302 *
303 * @result
304 * A newly-allocated and initialized {@link image4_environment_t} object. The
305 * caller is responsible for disposing of this object with
306 * {@link image4_environment_destroy} when it is no longer needed.
307 *
308 * If insufficient resources were available to allocate the object, or if the
309 * host runtime does not have an allocator, NULL is returned.
310 */
311IMAGE4_API_AVAILABLE_SPRING_2024
312OS_EXPORT OS_WARN_RESULT
313image4_environment_t *_Nullable
314image4_environment_new(
315 const image4_coprocessor_t *_Nullable coproc,
316 image4_coprocessor_handle_t handle);
317IMAGE4_XNU_AVAILABLE_DIRECT(image4_environment_new);
318
319/*!
320 * @function image4_environment_set_secure_boot
321 * Sets the desired secure boot level of the environment.
322 *
323 * @param nv
324 * The environment to manipulate.
325 *
326 * @param secure_boot
327 * The desired secure boot level.
328 *
329 * @discussion
330 * If the environment designated by the coprocessor and handle does not support
331 * secure boot, this is a no-op.
332 */
333IMAGE4_API_AVAILABLE_SPRING_2024
334OS_EXPORT OS_NONNULL1
335void
336image4_environment_set_secure_boot(
337 image4_environment_t *nv,
338 image4_secure_boot_t secure_boot);
339IMAGE4_XNU_AVAILABLE_DIRECT(image4_environment_set_secure_boot);
340
341/*!
342 * @function image4_environment_set_nonce_domain
343 * Sets the nonce domain number for the environment. This value will be returned
344 * as the value for the coprocessor's nonce domain property during environment
345 * iteration (e.g. if the environment is a Cryptex1 coprocessor handle, the ndom
346 * property).
347 *
348 * @param nv
349 * The environment to modify.
350 *
351 * @param nonce_domain
352 * The nonce domain number to set.
353 *
354 * @discussion
355 * This operation does not impact trust evaluation, which always defers to the
356 * nonce domain signed into the manifest if one is present. It is intended to
357 * support two workflows:
358 *
359 * 1. Constructing a personalization request using the callbacks associated
360 * with {@link image4_environment_identify} by allowing all the code that
361 * sets the values of the TSS request to reside in the identifier
362 * callbacks
363 * 2. Related to the above, performing nonce management operations on the
364 * nonce slot associated by the given domain (e.g. generating a proposal
365 * nonce with {@link image4_environment_generate_nonce_proposal})
366 *
367 * Certain coprocessor environments recognize a nonce domain entitlement, but
368 * only one valid value for that entitlement (e.g.
369 * {@link IMAGE4_COPROCESSOR_HANDLE_CRYPTEX1_BOOT}). These environments do not
370 * require the nonce domain to be set; it is automatically recognized based on
371 * the static properties of the coprocessor.
372 */
373IMAGE4_API_AVAILABLE_SPRING_2024
374OS_EXPORT OS_NONNULL1
375void
376image4_environment_set_nonce_domain(
377 image4_environment_t *nv,
378 uint32_t nonce_domain);
379IMAGE4_XNU_AVAILABLE_DIRECT(image4_environment_set_nonce_domain);
380
381/*!
382 * @function image4_environment_set_callbacks
383 * Sets the callbacks for an environment.
384 *
385 * @param nv
386 * The environment to manipulate.
387 *
388 * @param callbacks
389 * The callback structure.
390 *
391 * @param _ctx
392 * The caller-defined context to be passed to each callback.
393 */
394IMAGE4_API_AVAILABLE_SPRING_2024
395OS_EXPORT OS_NONNULL1 OS_NONNULL2
396void
397image4_environment_set_callbacks(
398 image4_environment_t *nv,
399 const image4_environment_callbacks_t *callbacks,
400 void *_Nullable _ctx);
401IMAGE4_XNU_AVAILABLE_DIRECT(image4_environment_set_callbacks);
402
403/*!
404 * @function image4_environment_identify
405 * Identifies the environment and provides the identity via the callbacks
406 * specified in the {@link image4_environment_callbacks_t} structure set for
407 * the environment.
408 *
409 * @param nv
410 * The environment to identify.
411 *
412 * @discussion
413 * If no callbacks were provided, or if no identifier callbacks were set in the
414 * callback structure, the implementation's behavior is undefined.
415 */
416IMAGE4_API_AVAILABLE_SPRING_2024
417OS_EXPORT OS_NONNULL1
418void
419image4_environment_identify(
420 const image4_environment_t *nv);
421IMAGE4_XNU_AVAILABLE_DIRECT(image4_environment_identify);
422
423/*!
424 * @function image4_environment_copy_nonce_digest
425 * Copies the digest of the specified nonce.
426 *
427 * @param nv
428 * The environment to query.
429 *
430 * @param digest
431 * Upon successful return, the digest of the live nonce for the environment. On
432 * failure, the contents of this structure are undefined.
433 *
434 * @result
435 * Upon success, zero is returned. Otherwise, the implementation may directly
436 * return one of the following POSIX error codes:
437 *
438 * [EPERM] The caller lacks the entitlement required to access the
439 * desired nonce
440 * [ENOTSUP] The environment does not manage a nonce for anti-replay
441 * [ESTALE] The nonce has been invalidated and will not be available until
442 * the next boot
443 */
444IMAGE4_API_AVAILABLE_SPRING_2024
445OS_EXPORT OS_WARN_RESULT OS_NONNULL1 OS_NONNULL2
446errno_t
447image4_environment_copy_nonce_digest(
448 const image4_environment_t *nv,
449 image4_nonce_digest_t *digest);
450IMAGE4_XNU_AVAILABLE_DIRECT(image4_environment_copy_nonce_digest);
451
452/*!
453 * @function image4_environment_roll_nonce
454 * Invalidates the live nonce for the environment such that a new nonce will be
455 * generated at the next boot.
456 *
457 * @param nv
458 * The environment to manipulate.
459 *
460 * @result
461 * Upon success, zero is returned. Otherwise, the implementation may directly
462 * return one of the following POSIX error codes:
463 *
464 * [EPERM] The caller lacks the entitlement required to access the
465 * desired nonce
466 * [ENOTSUP] The environment does not manage a nonce for anti-replay
467 */
468IMAGE4_API_AVAILABLE_SPRING_2024
469OS_EXPORT OS_WARN_RESULT OS_NONNULL1
470errno_t
471image4_environment_roll_nonce(
472 const image4_environment_t *nv);
473IMAGE4_XNU_AVAILABLE_DIRECT(image4_environment_roll_nonce);
474
475/*!
476 * @function image4_environment_generate_nonce_proposal
477 * Generates a nonce proposal for the environment and returns the hash of the
478 * proposal.
479 *
480 * @param nv
481 * The environment to manipulate.
482 *
483 * @param digest
484 * Upon successful return, the digest of the nonce proposal which was generated.
485 * On failure, the contents of this structure are undefined.
486 *
487 * @result
488 * Upon success, zero is returned. Otherwise, the implementation may directly
489 * return one of the following POSIX error codes:
490 *
491 * [EPERM] The caller lacks the entitlement required to manipulate the
492 * desired nonce
493 * [ENOTSUP] The environment does not manage a nonce for anti-replay
494 */
495IMAGE4_API_AVAILABLE_SPRING_2024
496OS_EXPORT OS_WARN_RESULT OS_NONNULL1 OS_NONNULL2
497errno_t
498image4_environment_generate_nonce_proposal(
499 const image4_environment_t *nv,
500 image4_nonce_digest_t *digest);
501IMAGE4_XNU_AVAILABLE_DIRECT(image4_environment_generate_nonce_proposal);
502
503/*!
504 * @function image4_environment_commit_nonce_proposal
505 * Commits the nonce proposal corresponding to the digest provided by the caller
506 * such that it will be accepted and live at the next boot.
507 *
508 * @param nv
509 * The environment to manipulate.
510 *
511 * @param digest
512 * The digest of the proposal to commit.
513 *
514 * @result
515 * Upon success, zero is returned. Otherwise, the implementation may directly
516 * return one of the following POSIX error codes:
517 *
518 * [EPERM] The caller lacks the entitlement required to manipulate the
519 * desired nonce
520 * [ENOTSUP] The environment does not manage a nonce for anti-replay
521 * [ENODEV] There is no proposal for the given nonce
522 * [EILSEQ] The digest provided by the caller does not correspond to the
523 * active proposal; this may occur if another subsystem
524 * generates a proposal for the environment
525 */
526IMAGE4_API_AVAILABLE_SPRING_2024
527OS_EXPORT OS_WARN_RESULT OS_NONNULL1 OS_NONNULL2
528errno_t
529image4_environment_commit_nonce_proposal(
530 const image4_environment_t *nv,
531 const image4_nonce_digest_t *digest);
532IMAGE4_XNU_AVAILABLE_DIRECT(image4_environment_commit_nonce_proposal);
533
534/*!
535 * @function image4_environment_get_nonce_handle
536 * Obtains the appropriate nonce handle to include in a signing request for the
537 * environment.
538 *
539 * @param nv
540 * The environment to query.
541 *
542 * @param handle
543 * Upon successful return, the handle appropriate for the signing request's
544 * nonce domain field. On failure, this parameter's value is undefined.
545 *
546 * @result
547 * Upon success, zero is returned. Otherwise, the implementation may directly
548 * return one of the following POSIX error codes:
549 *
550 * [ENOTSUP] The environment does not manage a nonce for anti-replay
551 * [ENOENT] The environment does not support identifing a nonce by its
552 * handle in the personalization request
553 *
554 * @discussion
555 * This function is not implemented and will be removed. See discussion in
556 * {@link image4_environment_set_nonce_handle} for guidance as to how to
557 * implement the relevant workflows.
558 */
559IMAGE4_API_AVAILABLE_SPRING_2024
560OS_EXPORT OS_WARN_RESULT OS_NONNULL1 OS_NONNULL2
561errno_t
562image4_environment_get_nonce_handle(
563 const image4_environment_t *nv,
564 uint64_t *handle);
565IMAGE4_XNU_AVAILABLE_DIRECT(image4_environment_get_nonce_handle);
566
567/*!
568 * @function image4_environment_destroy
569 * Disposes an environment object which was created via
570 * {@link image4_environment_new}.
571 *
572 * @param nv
573 * A pointer to the environment object. Upon return, this storage will be set to
574 * NULL. If the object pointed to by this parameter is NULL, this is a no-op.
575 *
576 * @discussion
577 * If this routine is called on an environment object which was not allocated,
578 * it is a no-op.
579 */
580IMAGE4_API_AVAILABLE_SPRING_2024
581OS_EXPORT OS_NONNULL1
582void
583image4_environment_destroy(
584 image4_environment_t *_Nonnull *_Nullable nv);
585IMAGE4_XNU_AVAILABLE_DIRECT(image4_environment_destroy);
586
587OS_ASSUME_PTR_ABI_SINGLE_END
588OS_ASSUME_NONNULL_END
589__END_DECLS
590
591#endif // __IMAGE4_API_ENVIRONMENT_H
592