1 /*! 2 * @header 3 * Provides an interface for managing nonces to govern the lifetime of a 4 * personalization performed with TSS. A nonce managed by this interface may 5 * be used in a TSS signing request as the value for the BNCH tag. 6 * 7 * These interfaces require the caller to possess the 8 * 9 * com.apple.private.security.AppleImage4.user-client 10 * 11 * entitlement. 12 * 13 * @section Threat Model 14 * The adversary possesses the following: 15 * 16 * 1. a manifest which was previously valid but has since been invalidated 17 * by rolling the nonce associated with it 18 * 2. user-level code execution 19 * 3. knowledge of the raw nonce value for the previously-valid manifest 20 * 21 * The defense against this adversary is a system in which knowledge of the raw 22 * nonce is insufficient to impact the evaluation of a personalization. This 23 * system has the following characteristics: 24 * 25 * 1. A nonce seed is stored in an nvram variable which is only writable by 26 * the kernel 27 * 2. When making a new signing request, the nonce seed is encrypted by a 28 * UID1-derived key in-kernel and then hashed -- the output of this 29 * operation the nonce to be used in the signing request 30 * 3. On boot, AppleImage4 obtains the nonce seed from nvram and stores it 31 * in a data structure which will be covered by KTRR 32 * 4. When evaluating a manifest, AppleImage4 reads the raw nonce from the 33 * KTRR-covered data structure and validates it with the same 34 * transformation as was done in (2) 35 * 5. When the nonce is to be invalidated, AppleImage4 sets a flag in an 36 * nvram variable which is only writable by the kernel 37 * 6. On the subsequent boot, AppleImage4 notices the flag, generates a new 38 * nonce and repeats the procedure in (3) 39 * 40 * In this system, the raw nonce seed never leaves the kernel, and the nonce 41 * itself is a non-reversible representation of the seed. 42 */ 43 44 45 #ifndef __IMG4_NONCE_H 46 #define __IMG4_NONCE_H 47 48 #ifndef __IMG4_INDIRECT 49 #error "Please #include <img4/firmware.h> instead of this file directly" 50 #endif // __IMG4_INDIRECT 51 52 /*! 53 * @typedef img4_nonce_domain_t 54 * An opaque type describing a nonce domain. 55 */ 56 IMG4_API_AVAILABLE_20181106 57 typedef struct _img4_nonce_domain img4_nonce_domain_t; 58 59 /*! 60 * @const IMG4_NONCE_STRUCT_VERSION 61 * The version of the {@link img4_nonce_t} structure supported by the 62 * implementation. 63 */ 64 #define IMG4_NONCE_STRUCT_VERSION ((img4_struct_version_t)0) 65 #define IMG4_NONCE_VERSION IMG4_NONCE_STRUCT_VERSION 66 67 /*! 68 * @const IMG4_NONCE_MAX_LENGTH 69 * The maximum length of a nonce. Currently, this is the length of a SHA2-384 70 * hash. 71 */ 72 #define IMG4_NONCE_MAX_LENGTH (48u) 73 74 /*! 75 * @typedef img4_nonce_domain_index_t 76 * An enumeration describing nonce domains. 77 * 78 * @const IMG4_NONCE_DOMAIN_INDEX_TEST 79 * The enumerated constant corresponding to the internal test nonce domain. 80 * 81 * @const IMG4_NONCE_DOMAIN_INDEX_TRUST_CACHE 82 * The enumerated constant corresponding to 83 * {@link IMG4_NONCE_DOMAIN_TRUST_CACHE}. 84 * 85 * @const IMG4_NONCE_DOMAIN_INDEX_PDI 86 * The enumerated constant corresponding to {@link IMG4_NONCE_DOMAIN_TRUST_PDI}. 87 * 88 * @const IMG4_NONCE_DOMAIN_INDEX_CRYPTEX 89 * The enumerated constant corresponding to {@link IMG4_NONCE_DOMAIN_CRYPTEX}. 90 * 91 * @const IMG4_NONCE_DOMAIN_INDEX_DDI 92 * The enumerated constant corresponding to {@link IMG4_NONCE_DOMAIN_DDI}. 93 * 94 * @const IMG4_NONCE_DOMAIN_INDEX_EPHEMERAL_CRYPTEX 95 * The enumerated constant corresponding to 96 * {@link IMG4_NONCE_DOMAIN_EPHEMERAL_CRYPTEX}. 97 * 98 * @const IMG4_NONCE_DOMAIN_INDEX_CRYPTEX1_SNUF_STUB 99 * The enumerated constant corresponding to 100 * {@link IMG4_NONCE_DOMAIN_CRYPTEX1_SNUF_STUB}. 101 * 102 * @const IMG4_NONCE_DOMAIN_INDEX_CRYPTEX1_BOOT 103 * The enumerated constant corresponding to 104 * {@link IMG4_NONCE_DOMAIN_CRYPTEX1_BOOT}. 105 * 106 * @const IMG4_NONCE_DOMAIN_INDEX_CRYPTEX1_ASSET 107 * The enumerated constant corresponding to 108 * {@link IMG4_NONCE_DOMAIN_CRYPTEX1_ASSET}. 109 * 110 * @const _IMG4_NONCE_DOMAIN_INDEX_CNT 111 * A sentinel value indicating the number of nonce domains. 112 */ 113 IMG4_API_AVAILABLE_20210521 114 OS_CLOSED_ENUM(img4_nonce_domain_index, uint64_t, 115 IMG4_NONCE_DOMAIN_INDEX_TEST = 0, 116 IMG4_NONCE_DOMAIN_INDEX_TRUST_CACHE, 117 IMG4_NONCE_DOMAIN_INDEX_PDI, 118 IMG4_NONCE_DOMAIN_INDEX_CRYPTEX, 119 IMG4_NONCE_DOMAIN_INDEX_DDI, 120 IMG4_NONCE_DOMAIN_INDEX_EPHEMERAL_CRYPTEX, 121 IMG4_NONCE_DOMAIN_INDEX_CRYPTEX1_SNUF_STUB, 122 IMG4_NONCE_DOMAIN_INDEX_CRYPTEX1_BOOT, 123 IMG4_NONCE_DOMAIN_INDEX_CRYPTEX1_ASSET, 124 _IMG4_NONCE_DOMAIN_INDEX_CNT, 125 ); 126 127 /*! 128 * @typedef img4_nonce_t 129 * A structure describing a nonce. 130 * 131 * @field i4n_version 132 * The version of the structure. When declaring this structure, you must 133 * initialize this field to {@link IMG4_NONCE_VERSION}. 134 * 135 * @field i4n_nonce 136 * The bytes comprising the nonce. 137 * 138 * @field i4n_length 139 * The length of the nonce. Will be at most {@link IMG4_NONCE_MAX_LENGTH}. 140 * 141 * @discussion 142 * The {@link i4n_nonce} field was previously const. This was a terrible idea, 143 * and the const storage qualifier was removed without adjusting the structure 144 * version. 145 */ 146 IMG4_API_AVAILABLE_20181106 147 typedef struct _img4_nonce { 148 img4_struct_version_t i4n_version; 149 uint8_t i4n_nonce[IMG4_NONCE_MAX_LENGTH]; 150 uint32_t i4n_length; 151 } img4_nonce_t; 152 153 /*! 154 * @const IMG4_NONCE_INIT 155 * A convenience initializer for {@link img4_nonce_t} which ensures that the 156 * {@link i4n_version} field is properly initialized. 157 */ 158 #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L 159 #define IMG4_NONCE_INIT (img4_nonce_t){.i4n_version = IMG4_NONCE_STRUCT_VERSION} 160 #elif defined(__cplusplus) && __cplusplus >= 201103L 161 #define IMG4_NONCE_INIT (img4_nonce_t{IMG4_NONCE_STRUCT_VERSION}) 162 #elif defined(__cplusplus) 163 #define IMG4_NONCE_INIT \ 164 (img4_nonce_t((img4_nonce_t){IMG4_NONCE_STRUCT_VERSION})) 165 #else 166 #define IMG4_NONCE_INIT {IMG4_NONCE_STRUCT_VERSION} 167 #endif 168 169 /*! 170 * @const IMG4_NONCE_ZERO 171 * A convenience initializer for {@link img4_nonce_t} which initializes a 48- 172 * byte nonce of all zeroes. 173 */ 174 #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L 175 #define IMG4_NONCE_ZERO (img4_nonce_t){ \ 176 .i4n_version = IMG4_NONCE_STRUCT_VERSION, \ 177 .i4n_nonce = {0}, \ 178 .i4n_length = IMG4_NONCE_MAX_LENGTH, \ 179 } 180 #endif 181 182 /*! 183 * @const IMG4_NONCE_DOMAIN_TRUST_CACHE 184 * The nonce domain governing trust cache personalizations. Use of this domain 185 * requires the 186 * 187 * com.apple.private.img4.nonce.trust-cache 188 * 189 * entitlement. 190 */ 191 #if !XNU_KERNEL_PRIVATE 192 IMG4_API_AVAILABLE_20181106 193 OS_EXPORT 194 const struct _img4_nonce_domain _img4_nonce_domain_trust_cache; 195 #define IMG4_NONCE_DOMAIN_TRUST_CACHE (&_img4_nonce_domain_trust_cache) 196 #else 197 #define IMG4_NONCE_DOMAIN_TRUST_CACHE (img4if->i4if_v1.nonce_domain_trust_cache) 198 #endif 199 200 /*! 201 * @const IMG4_NONCE_DOMAIN_PDI 202 * The nonce domain governing disk image personalizations. Use of this domain 203 * requires the 204 * 205 * com.apple.private.img4.nonce.pdi 206 * 207 * entitlement. The nonce for this domain is regenerated once every boot. 208 */ 209 #if !XNU_KERNEL_PRIVATE 210 IMG4_API_AVAILABLE_20181106 211 OS_EXPORT 212 const struct _img4_nonce_domain _img4_nonce_domain_pdi; 213 #define IMG4_NONCE_DOMAIN_PDI (&_img4_nonce_domain_pdi) 214 #else 215 #define IMG4_NONCE_DOMAIN_PDI (img4if->i4if_v3.nonce_domain_pdi) 216 #endif 217 218 /*! 219 * @const IMG4_NONCE_DOMAIN_CRYPTEX 220 * The nonce domain governing cryptex personalizations. Use of this domain 221 * requires the 222 * 223 * com.apple.private.img4.nonce.cryptex 224 * 225 * entitlement. 226 */ 227 #if !XNU_KERNEL_PRIVATE 228 IMG4_API_AVAILABLE_20181106 229 OS_EXPORT 230 const struct _img4_nonce_domain _img4_nonce_domain_cryptex; 231 #define IMG4_NONCE_DOMAIN_CRYPTEX (&_img4_nonce_domain_cryptex) 232 #else 233 #define IMG4_NONCE_DOMAIN_CRYPTEX (img4if->i4if_v3.nonce_domain_cryptex) 234 #endif 235 236 /*! 237 * @const IMG4_NONCE_DOMAIN_DDI 238 * The nonce domain governing developer disk image personalizations. Use of this 239 * domain requires the 240 * 241 * com.apple.private.img4.nonce.ddi 242 * 243 * entitlement. 244 */ 245 #if !XNU_KERNEL_PRIVATE 246 IMG4_API_AVAILABLE_20181106 247 OS_EXPORT 248 const struct _img4_nonce_domain _img4_nonce_domain_ddi; 249 #define IMG4_NONCE_DOMAIN_DDI (&_img4_nonce_domain_ddi) 250 #else 251 #define IMG4_NONCE_DOMAIN_DDI (img4if->i4if_v12.nonce_domain_ddi) 252 #endif 253 254 /*! 255 * @const IMG4_NONCE_DOMAIN_EPHEMERAL_CRYPTEX 256 * The nonce domain governing ephemeral cryptex personalizations. Use of this 257 * domain requires the 258 * 259 * com.apple.private.img4.nonce.ephemeral-cryptex 260 * 261 * entitlement. 262 */ 263 #if !XNU_KERNEL_PRIVATE 264 IMG4_API_AVAILABLE_20210305 265 OS_EXPORT 266 const struct _img4_nonce_domain _img4_nonce_domain_ephemeral_cryptex; 267 #define IMG4_NONCE_DOMAIN_EPHEMERAL_CRYPTEX \ 268 (&_img4_nonce_domain_ephemeral_cryptex) 269 #else 270 #define IMG4_NONCE_DOMAIN_EPHEMERAL_CRYPTEX \ 271 (img4if->i4if_v12.nonce_domain_ephemeral_cryptex) 272 #endif 273 274 /*! 275 * @const IMG4_NONCE_DOMAIN_CRYPTEX1_SNUF_STUB 276 * The nonce domain which acts as a null stub for the snuf value for Cryptex1 277 * processors. This domain corresponds to a value of 0 for the 278 * Cryptex1,NonceDomain tag. Use of this domain requires the 279 * 280 * com.apple.private.img4.nonce.cryptex1.snuf-stub 281 * 282 * entitlement. 283 */ 284 #if !XNU_KERNEL_PRIVATE 285 IMG4_API_AVAILABLE_20220322 286 OS_EXPORT 287 const struct _img4_nonce_domain _img4_nonce_domain_cryptex1_snuf_stub; 288 #define IMG4_NONCE_DOMAIN_CRYPTEX1_SNUF_STUB \ 289 (&_img4_nonce_domain_cryptex1_snuf_stub) 290 #else 291 #define IMG4_NONCE_DOMAIN_CRYPTEX1_SNUF_STUB \ 292 (img4if->i4if_v18.nonce_domain_cryptex1_snuf_stub) 293 #endif 294 295 /*! 296 * @const IMG4_NONCE_DOMAIN_CRYPTEX1_BOOT 297 * The nonce domain governing personalizations for the virtual Cryptex1 298 * coprocessor's boot objects. This domain corresponds to a value of 1 for the 299 * Cryptex1,NonceDomain tag. Use of this domain requires the 300 * 301 * com.apple.private.img4.nonce.cryptex1.boot 302 * 303 * entitlement. 304 */ 305 #if !XNU_KERNEL_PRIVATE 306 IMG4_API_AVAILABLE_20211112 307 OS_EXPORT 308 const struct _img4_nonce_domain _img4_nonce_domain_cryptex1_boot; 309 #define IMG4_NONCE_DOMAIN_CRYPTEX1_BOOT \ 310 (&_img4_nonce_domain_cryptex1_boot) 311 #else 312 #define IMG4_NONCE_DOMAIN_CRYPTEX1_BOOT \ 313 (img4if->i4if_v16.nonce_domain_cryptex1_boot) 314 #endif 315 316 /*! 317 * @const IMG4_NONCE_DOMAIN_CRYPTEX1_ASSET 318 * The nonce domain governing personalizations for the virtual Cryptex1 319 * coprocessor's asset brain objects. This domain corresponds to a value of 2 320 * for the Cryptex1,NonceDomain tag. Use of this domain requires the 321 * 322 * com.apple.private.img4.nonce.cryptex1.asset 323 * 324 * entitlement. 325 */ 326 #if !XNU_KERNEL_PRIVATE 327 IMG4_API_AVAILABLE_20211112 328 OS_EXPORT 329 const struct _img4_nonce_domain _img4_nonce_domain_cryptex1_asset; 330 #define IMG4_NONCE_DOMAIN_CRYPTEX1_ASSET \ 331 (&_img4_nonce_domain_cryptex1_asset) 332 #else 333 #define IMG4_NONCE_DOMAIN_CRYPTEX1_ASSET \ 334 (img4if->i4if_v16.nonce_domain_cryptex1_asset) 335 #endif 336 337 /*! 338 * @function img4_nonce_domain_copy_nonce 339 * Copies the current value of the nonce in the given domain. 340 * 341 * @param nd 342 * The nonce domain. 343 * 344 * @param n 345 * Upon successful return, storage that will contain the current nonce. The 346 * provided structure's {@link i4n_version} must be initialized to 347 * {@link IMG4_NONCE_VERSION}. 348 * 349 * @result 350 * Upon success, zero is returned. The implementation may also return one of the 351 * following error codes directly: 352 * 353 * [ESTALE] The nonce for the given domain has been invalidated, and the 354 * host must reboot in order to generate a new one 355 * [EPERM] The caller lacked the entitlement necessary to read the 356 * given nonce 357 * [ENOTSUP] Nonce management is not available on the host 358 * [EACCES] The nonce requested is not accessible in this environment 359 */ 360 #if !XNU_KERNEL_PRIVATE 361 IMG4_API_AVAILABLE_20210305 362 OS_EXPORT OS_WARN_RESULT OS_NONNULL1 OS_NONNULL2 363 errno_t 364 img4_nonce_domain_copy_nonce(const img4_nonce_domain_t *nd, img4_nonce_t *n); 365 #else 366 #define img4_nonce_domain_copy_nonce(...) \ 367 (img4if->i4if_v1.nonce_domain_copy_nonce(__VA_ARGS__)) 368 #endif 369 370 /*! 371 * @function img4_nonce_domain_roll_nonce 372 * Invalidates the current nonce for the given domain and forces a re-generation 373 * of the domain's nonce seed at the next boot. 374 * 375 * @param nd 376 * The nonce domain. 377 * 378 * @result 379 * Upon success, zero is returned. The kernel implementation will never return 380 * a non-zero code. The userspace implementation may return one of the following 381 * error codes directly: 382 * 383 * [EPERM] The caller lacked the entitlement necessary to roll the 384 * given nonce 385 * [EROFS] The boot mode didn't allow committing to non-volatile storage 386 * [ENOTSUP] Nonce management is not available on the host 387 * [EACCES] The nonce requested is not accessible in this environment 388 */ 389 #if !XNU_KERNEL_PRIVATE 390 IMG4_API_AVAILABLE_20181106 391 OS_EXPORT OS_WARN_RESULT OS_NONNULL1 392 errno_t 393 img4_nonce_domain_roll_nonce(const img4_nonce_domain_t *nd); 394 #else 395 #define img4_nonce_domain_roll_nonce(...) \ 396 (img4if->i4if_v1.nonce_domain_roll_nonce(__VA_ARGS__)) 397 #endif 398 399 /*! 400 * @function img4_nonce_domain_preroll_nonce 401 * Generates a new nonce seed and returns the resulting hash. The new nonce seed 402 * will be in force at the next reboot if and only if the boot manifest hash 403 * changes. Otherwise, the current nonce seed value will remain stable (modulo 404 * the regeneration policy associated with its domain). 405 * 406 * @param nd 407 * The nonce domain. 408 * 409 * @param n 410 * Upon successful return, storage that will contain the current nonce. The 411 * provided structure's {@link i4n_version} must be initialized to 412 * {@link IMG4_NONCE_VERSION}. 413 * 414 * @result 415 * Upon success, zero is returned. The kernel implementation will never return 416 * a non-zero code. The userspace implementation may return one of the following 417 * error codes directly: 418 * 419 * [EPERM] The caller lacked the entitlement necessary to roll the 420 * given nonce 421 * [EROFS] The boot mode didn't allow committing to non-volatile storage 422 * [ENOTSUP] Nonce management is not available on the host 423 * [EACCES] The nonce requested is not accessible in this environment 424 */ 425 #if !XNU_KERNEL_PRIVATE 426 IMG4_API_AVAILABLE_FALL_2021_B 427 OS_EXPORT OS_WARN_RESULT OS_NONNULL1 OS_NONNULL2 428 errno_t 429 img4_nonce_domain_preroll_nonce(const img4_nonce_domain_t *nd, img4_nonce_t *n); 430 #else 431 #define img4_nonce_domain_preroll_nonce(...) \ 432 (img4if->i4if_v14.nonce_domain_preroll_nonce(__VA_ARGS__)) 433 #endif 434 435 #endif // __IMG4_NONCE_H 436