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 |
16 | OS_ASSUME_NONNULL_BEGIN |
17 | OS_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 | */ |
24 | typedef 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 | */ |
59 | typedef 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 | */ |
101 | typedef 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 | */ |
125 | typedef 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 | */ |
149 | typedef 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 | */ |
176 | typedef 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 | */ |
218 | typedef 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 | */ |
242 | struct _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 | */ |
274 | IMAGE4_API_AVAILABLE_SPRING_2024 |
275 | OS_EXPORT OS_WARN_RESULT OS_NONNULL1 |
276 | image4_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) |
288 | IMAGE4_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 | */ |
311 | IMAGE4_API_AVAILABLE_SPRING_2024 |
312 | OS_EXPORT OS_WARN_RESULT |
313 | image4_environment_t *_Nullable |
314 | image4_environment_new( |
315 | const image4_coprocessor_t *_Nullable coproc, |
316 | image4_coprocessor_handle_t handle); |
317 | IMAGE4_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 | */ |
333 | IMAGE4_API_AVAILABLE_SPRING_2024 |
334 | OS_EXPORT OS_NONNULL1 |
335 | void |
336 | image4_environment_set_secure_boot( |
337 | image4_environment_t *nv, |
338 | image4_secure_boot_t secure_boot); |
339 | IMAGE4_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 | */ |
373 | IMAGE4_API_AVAILABLE_SPRING_2024 |
374 | OS_EXPORT OS_NONNULL1 |
375 | void |
376 | image4_environment_set_nonce_domain( |
377 | image4_environment_t *nv, |
378 | uint32_t nonce_domain); |
379 | IMAGE4_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 | */ |
394 | IMAGE4_API_AVAILABLE_SPRING_2024 |
395 | OS_EXPORT OS_NONNULL1 OS_NONNULL2 |
396 | void |
397 | image4_environment_set_callbacks( |
398 | image4_environment_t *nv, |
399 | const image4_environment_callbacks_t *callbacks, |
400 | void *_Nullable _ctx); |
401 | IMAGE4_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 | */ |
416 | IMAGE4_API_AVAILABLE_SPRING_2024 |
417 | OS_EXPORT OS_NONNULL1 |
418 | void |
419 | image4_environment_identify( |
420 | const image4_environment_t *nv); |
421 | IMAGE4_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 | */ |
444 | IMAGE4_API_AVAILABLE_SPRING_2024 |
445 | OS_EXPORT OS_WARN_RESULT OS_NONNULL1 OS_NONNULL2 |
446 | errno_t |
447 | image4_environment_copy_nonce_digest( |
448 | const image4_environment_t *nv, |
449 | image4_nonce_digest_t *digest); |
450 | IMAGE4_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 | */ |
468 | IMAGE4_API_AVAILABLE_SPRING_2024 |
469 | OS_EXPORT OS_WARN_RESULT OS_NONNULL1 |
470 | errno_t |
471 | image4_environment_roll_nonce( |
472 | const image4_environment_t *nv); |
473 | IMAGE4_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 | */ |
495 | IMAGE4_API_AVAILABLE_SPRING_2024 |
496 | OS_EXPORT OS_WARN_RESULT OS_NONNULL1 OS_NONNULL2 |
497 | errno_t |
498 | image4_environment_generate_nonce_proposal( |
499 | const image4_environment_t *nv, |
500 | image4_nonce_digest_t *digest); |
501 | IMAGE4_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 | */ |
526 | IMAGE4_API_AVAILABLE_SPRING_2024 |
527 | OS_EXPORT OS_WARN_RESULT OS_NONNULL1 OS_NONNULL2 |
528 | errno_t |
529 | image4_environment_commit_nonce_proposal( |
530 | const image4_environment_t *nv, |
531 | const image4_nonce_digest_t *digest); |
532 | IMAGE4_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 | */ |
559 | IMAGE4_API_AVAILABLE_SPRING_2024 |
560 | OS_EXPORT OS_WARN_RESULT OS_NONNULL1 OS_NONNULL2 |
561 | errno_t |
562 | image4_environment_get_nonce_handle( |
563 | const image4_environment_t *nv, |
564 | uint64_t *handle); |
565 | IMAGE4_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 | */ |
580 | IMAGE4_API_AVAILABLE_SPRING_2024 |
581 | OS_EXPORT OS_NONNULL1 |
582 | void |
583 | image4_environment_destroy( |
584 | image4_environment_t *_Nonnull *_Nullable nv); |
585 | IMAGE4_XNU_AVAILABLE_DIRECT(image4_environment_destroy); |
586 | |
587 | OS_ASSUME_PTR_ABI_SINGLE_END |
588 | OS_ASSUME_NONNULL_END |
589 | __END_DECLS |
590 | |
591 | #endif // __IMAGE4_API_ENVIRONMENT_H |
592 | |