2 * Copyright (c) 2018 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 #import <TargetConditionals.h>
27 #import "SecKeybagSupport.h"
29 #if __has_include(<libaks.h>)
33 #if __has_include(<libaks_ref_key.h>)
34 #import <libaks_ref_key.h>
37 #if __has_include(<MobileKeyBag/MobileKeyBag.h>)
38 #import <MobileKeyBag/MobileKeyBag.h>
41 #include <os/variant_private.h>
43 #import <ctkclient/ctkclient.h>
44 #import <coreauthd_spi.h>
46 #import <LocalAuthentication/LAPublicDefines.h>
47 #import <LocalAuthentication/LAPrivateDefines.h>
48 #import <LocalAuthentication/LACFSupport.h>
49 #import <SecurityFoundation/SFEncryptionOperation.h>
52 bool hwaes_key_available(void)
57 #define SET_FLAG_ON(v, flag) v |= (flag)
58 #define SET_FLAG_OFF(v, flag) v &= ~(flag)
60 @interface SecMockAKS ()
61 @property (class, readonly) NSMutableDictionary<NSNumber*, NSNumber*>* lockedStates;
62 @property (class, readonly) dispatch_queue_t mutabilityQueue;
65 @implementation SecMockAKS
66 static NSMutableDictionary* _lockedStates = nil;
67 static dispatch_queue_t _mutabilityQueue = nil;
68 static keybag_state_t _keybag_state = keybag_state_unlocked | keybag_state_been_unlocked;
71 * Method that limit where this rather in-secure version of AKS can run
75 static dispatch_once_t onceToken;
76 dispatch_once(&onceToken, ^{
77 #if DEBUG || TARGET_OS_SIMULATOR
80 const char *argv0 = getprogname();
82 if (strcmp(argv0, "securityd") == 0 || strcmp(argv0, "secd") == 0) {
85 if (os_variant_has_internal_content("securityd")) {
88 #if TARGET_OS_IPHONE /* all three platforms: ios, watch, tvos */
89 if (os_variant_uses_ephemeral_storage("securityd")) {
92 if (os_variant_allows_internal_security_policies("securityd")) {
96 #endif /* TARGET_OS_IPHONE */
97 #endif /* !DEBUG || !TARGET_OS_SIMULATOR */
101 + (NSMutableDictionary*)lockedStates
103 if(_lockedStates == nil) {
104 _lockedStates = [NSMutableDictionary dictionary];
106 return _lockedStates;
109 + (dispatch_queue_t)mutabilityQueue
111 static dispatch_once_t onceToken;
112 dispatch_once(&onceToken, ^{
113 _mutabilityQueue = dispatch_queue_create("SecMockAKS", DISPATCH_QUEUE_SERIAL);
115 return _mutabilityQueue;
118 + (keybag_state_t)keybag_state
120 return _keybag_state;
123 + (void)setKeybag_state:(keybag_state_t)keybag_state
125 _keybag_state = keybag_state;
130 dispatch_sync(self.mutabilityQueue, ^{
131 [self.lockedStates removeAllObjects];
132 self.keybag_state = keybag_state_unlocked;
136 + (bool)isLocked:(keyclass_t)key_class
138 __block bool isLocked = false;
139 dispatch_sync(self.mutabilityQueue, ^{
140 NSNumber* key = [NSNumber numberWithInt:key_class];
141 isLocked = [self.lockedStates[key] boolValue];
151 + (bool)useGenerationCount
158 dispatch_sync(self.mutabilityQueue, ^{
159 self.lockedStates[[NSNumber numberWithInt:key_class_a]] = [NSNumber numberWithBool:YES];
160 self.lockedStates[[NSNumber numberWithInt:key_class_ak]] = [NSNumber numberWithBool:YES];
161 self.lockedStates[[NSNumber numberWithInt:key_class_aku]] = [NSNumber numberWithBool:YES];
162 self.lockedStates[[NSNumber numberWithInt:key_class_akpu]] = [NSNumber numberWithBool:YES];
164 SET_FLAG_ON(self.keybag_state, keybag_state_locked);
165 SET_FLAG_OFF(self.keybag_state, keybag_state_unlocked);
166 // don't touch keybag_state_been_unlocked; leave it as-is
170 // Simulate device being in "before first unlock"
173 dispatch_sync(self.mutabilityQueue, ^{
174 self.lockedStates[[NSNumber numberWithInt:key_class_a]] = [NSNumber numberWithBool:YES];
175 self.lockedStates[[NSNumber numberWithInt:key_class_ak]] = [NSNumber numberWithBool:YES];
176 self.lockedStates[[NSNumber numberWithInt:key_class_aku]] = [NSNumber numberWithBool:YES];
177 self.lockedStates[[NSNumber numberWithInt:key_class_akpu]] = [NSNumber numberWithBool:YES];
178 self.lockedStates[[NSNumber numberWithInt:key_class_c]] = [NSNumber numberWithBool:YES];
179 self.lockedStates[[NSNumber numberWithInt:key_class_ck]] = [NSNumber numberWithBool:YES];
180 self.lockedStates[[NSNumber numberWithInt:key_class_cku]] = [NSNumber numberWithBool:YES];
182 SET_FLAG_ON(self.keybag_state, keybag_state_locked);
183 SET_FLAG_OFF(self.keybag_state, keybag_state_unlocked);
184 SET_FLAG_OFF(self.keybag_state, keybag_state_been_unlocked);
188 + (void)unlockAllClasses
190 dispatch_sync(self.mutabilityQueue, ^{
191 [self.lockedStates removeAllObjects];
193 SET_FLAG_OFF(self.keybag_state, keybag_state_locked);
194 SET_FLAG_ON(self.keybag_state, keybag_state_unlocked);
195 SET_FLAG_ON(self.keybag_state, keybag_state_been_unlocked);
202 aks_load_bag(const void * data, int length, keybag_handle_t* handle)
209 aks_create_bag(const void * passcode, int length, keybag_type_t type, keybag_handle_t* handle)
211 [SecMockAKS unlockAllClasses];
217 aks_unload_bag(keybag_handle_t handle)
219 return kAKSReturnSuccess;
223 aks_save_bag(keybag_handle_t handle, void ** data, int * length)
225 assert(handle != bad_keybag_handle);
229 *data = calloc(1, 12);
230 memcpy(*data, "keybag dump", 12);
233 return kAKSReturnSuccess;
237 aks_get_system(keybag_handle_t special_handle, keybag_handle_t *handle)
240 return kAKSReturnSuccess;
244 aks_get_bag_uuid(keybag_handle_t handle, uuid_t uuid)
246 memcpy(uuid, "0123456789abcdf", sizeof(uuid_t));
247 return kAKSReturnSuccess;
250 kern_return_t aks_lock_bag(keybag_handle_t handle)
252 if (handle == KEYBAG_DEVICE) {
253 [SecMockAKS lockClassA];
255 return kAKSReturnSuccess;
258 kern_return_t aks_unlock_bag(keybag_handle_t handle, const void *passcode, int length)
260 if (handle == KEYBAG_DEVICE) {
261 [SecMockAKS unlockAllClasses];
263 return kAKSReturnSuccess;
266 kern_return_t aks_get_lock_state(keybag_handle_t handle, keybag_state_t *state)
268 *state = SecMockAKS.keybag_state;
269 return kAKSReturnSuccess;
272 //static uint8_t staticAKSKey[32] = "1234567890123456789012";
274 #define PADDINGSIZE 8
277 aks_wrap_key(const void * key, int key_size, keyclass_t key_class, keybag_handle_t handle, void * wrapped_key, int * wrapped_key_size_inout, keyclass_t * class_out)
279 [SecMockAKS trapdoor];
281 if ([SecMockAKS isSEPDown]) {
282 return kAKSReturnBusy;
285 // Assumes non-device keybags are asym
286 if ([SecMockAKS isLocked:key_class] && handle == KEYBAG_DEVICE) {
287 return kAKSReturnNoPermission;
290 if (class_out) { // Not a required parameter
291 *class_out = key_class;
292 if ([SecMockAKS useGenerationCount]) {
293 *class_out |= (key_class_last + 1);
297 if (key_size > APPLE_KEYSTORE_MAX_KEY_LEN) {
300 if (handle != KEYBAG_DEVICE) { // For now assumes non-device bags are asym
301 if (APPLE_KEYSTORE_MAX_ASYM_WRAPPED_KEY_LEN > *wrapped_key_size_inout) {
305 if (APPLE_KEYSTORE_MAX_SYM_WRAPPED_KEY_LEN > *wrapped_key_size_inout) {
310 *wrapped_key_size_inout = key_size + PADDINGSIZE;
311 memcpy(wrapped_key, key, key_size);
312 memset(((uint8_t *)wrapped_key) + key_size, 0xff, PADDINGSIZE);
313 return kAKSReturnSuccess;
317 aks_unwrap_key(const void * wrapped_key, int wrapped_key_size, keyclass_t key_class, keybag_handle_t handle, void * key, int * key_size_inout)
319 [SecMockAKS trapdoor];
321 if ([SecMockAKS isSEPDown]) {
322 return kAKSReturnBusy;
325 if ([SecMockAKS isLocked:key_class]) {
326 return kAKSReturnNoPermission;
329 if (wrapped_key_size < PADDINGSIZE) {
332 static const char expected_padding[PADDINGSIZE] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
333 if (memcmp(((const uint8_t *)wrapped_key) + (wrapped_key_size - PADDINGSIZE), expected_padding, PADDINGSIZE) != 0) {
334 return kAKSReturnDecodeError;
336 if (*key_size_inout < wrapped_key_size - PADDINGSIZE) {
339 *key_size_inout = wrapped_key_size - PADDINGSIZE;
340 memcpy(key, wrapped_key, *key_size_inout);
342 return kAKSReturnSuccess;
346 aks_ref_key_create(keybag_handle_t handle, keyclass_t cls, aks_key_type_t type, const uint8_t *params, size_t params_len, aks_ref_key_t *ot)
348 [SecMockAKS trapdoor];
350 // For now, mock AKS keys are all the same key
351 NSData* keyData = [NSData dataWithBytes:"1234567890123456789012345678901" length:32];
352 SFAESKeySpecifier* keySpecifier = [[SFAESKeySpecifier alloc] initWithBitSize:SFAESKeyBitSize256];
353 NSError* error = nil;
354 SFAESKey* key = [[SFAESKey alloc] initWithData:keyData specifier:keySpecifier error:&error];
357 return kAKSReturnError;
360 *ot = (__bridge_retained aks_ref_key_t)key;
361 return kAKSReturnSuccess;
365 aks_ref_key_encrypt(aks_ref_key_t handle,
366 const uint8_t *der_params, size_t der_params_len,
367 const void * data, size_t data_len,
368 void ** out_der, size_t * out_der_len)
370 [SecMockAKS trapdoor];
372 // No current error injection
373 NSError* error = nil;
374 NSData* nsdata = [NSData dataWithBytes:data length:data_len];
376 SFAESKey* key = (__bridge SFAESKey*)handle;
377 SFAuthenticatedEncryptionOperation* op = [[SFAuthenticatedEncryptionOperation alloc] initWithKeySpecifier:key.keySpecifier authenticationMode:SFAuthenticatedEncryptionModeGCM];
380 SFAuthenticatedCiphertext* ciphertext = [op encrypt:nsdata withKey:key error:&error];
382 if(error || !ciphertext || !out_der || !out_der_len) {
383 return kAKSReturnError;
386 //[NSKeyedUnarchiver unarchivedObjectOfClass:[SFAuthenticatedCiphertext class] fromData:_serializedHolder.ciphertext error:&error];
388 NSData* cipherBytes = [NSKeyedArchiver archivedDataWithRootObject:ciphertext requiringSecureCoding:YES error:&error];
389 if(error || !cipherBytes) {
390 return kAKSReturnError;
393 *out_der = calloc(1, cipherBytes.length);
395 memcpy(*out_der, cipherBytes.bytes, cipherBytes.length);
396 *out_der_len = cipherBytes.length;
398 return kAKSReturnSuccess;
402 aks_ref_key_decrypt(aks_ref_key_t handle,
403 const uint8_t *der_params, size_t der_params_len,
404 const void * data, size_t data_len,
405 void ** out_der, size_t * out_der_len)
407 [SecMockAKS trapdoor];
409 if (!out_der || !out_der_len || !data) {
410 return kAKSReturnError;
413 NSError* error = nil;
414 NSData* nsdata = [NSData dataWithBytes:data length:data_len];
416 SFAESKey* key = (__bridge SFAESKey*)handle;
418 NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:nsdata error:&error];
419 SFAuthenticatedCiphertext* ciphertext = [unarchiver decodeObjectOfClass:[SFAuthenticatedCiphertext class] forKey:NSKeyedArchiveRootObjectKey];
421 if(error || !ciphertext) {
422 return kAKSReturnError;
425 SFAuthenticatedEncryptionOperation* op = [[SFAuthenticatedEncryptionOperation alloc] initWithKeySpecifier:key.keySpecifier authenticationMode:SFAuthenticatedEncryptionModeGCM];
426 NSData* plaintext = [op decrypt:ciphertext withKey:key error:&error];
428 if(error || !plaintext) {
429 return kAKSReturnDecodeError;
432 *out_der = calloc(1, plaintext.length);
434 memcpy(*out_der, plaintext.bytes, plaintext.length);
435 *out_der_len = plaintext.length;
437 return kAKSReturnSuccess;
440 int aks_ref_key_wrap(aks_ref_key_t handle,
441 uint8_t *der_params, size_t der_params_len,
442 const uint8_t *key, size_t key_len,
443 void **out_der, size_t *out_der_len)
445 [SecMockAKS trapdoor];
447 return aks_ref_key_encrypt(handle, der_params, der_params_len, key, key_len, out_der, out_der_len);
450 int aks_ref_key_unwrap(aks_ref_key_t handle,
451 uint8_t *der_params, size_t der_params_len,
452 const uint8_t *wrapped, size_t wrapped_len,
453 void **out_der, size_t *out_der_len)
455 [SecMockAKS trapdoor];
457 return aks_ref_key_decrypt(handle, der_params, der_params_len, wrapped, wrapped_len, out_der, out_der_len);
462 aks_ref_key_delete(aks_ref_key_t handle, const uint8_t *der_params, size_t der_params_len)
464 return kAKSReturnSuccess;
468 aks_operation_optional_params(const uint8_t * access_groups, size_t access_groups_len, const uint8_t * external_data, size_t external_data_len, const void * acm_handle, int acm_handle_len, void ** out_der, size_t * out_der_len)
470 // ugh. Let's at least pretend we're doing something here.
471 assert((out_der && out_der_len) || !(out_der || out_der_len));
473 *out_der = calloc(1, 150);
474 memset(*out_der, 'A', 150);
478 return kAKSReturnSuccess;
481 int aks_ref_key_create_with_blob(keybag_handle_t keybag, const uint8_t *ref_key_blob, size_t ref_key_blob_len, aks_ref_key_t* handle)
483 aks_ref_key_create(keybag, 0, 0, NULL, 0, handle);
484 return kAKSReturnSuccess;
487 const uint8_t * aks_ref_key_get_blob(aks_ref_key_t refkey, size_t *out_blob_len)
490 return (const uint8_t *)"20";
493 aks_ref_key_free(aks_ref_key_t* key)
495 return kAKSReturnSuccess;
499 aks_ref_key_get_external_data(aks_ref_key_t refkey, size_t *out_external_data_len)
501 *out_external_data_len = 2;
502 return (const uint8_t *)"21";
506 aks_assert_hold(keybag_handle_t handle, uint32_t type, uint64_t timeout)
508 if ([SecMockAKS isLocked:key_class_ak]) {
509 return kAKSReturnNoPermission;
511 return kAKSReturnSuccess;
515 aks_assert_drop(keybag_handle_t handle, uint32_t type)
517 return kAKSReturnSuccess;
521 aks_generation(keybag_handle_t handle,
522 generation_option_t generation_option,
523 uint32_t * current_generation)
525 *current_generation = 0;
526 return kAKSReturnSuccess;
529 CFStringRef kMKBDeviceModeMultiUser = CFSTR("kMKBDeviceModeMultiUser");
530 CFStringRef kMKBDeviceModeSingleUser = CFSTR("kMKBDeviceModeSingleUser");
531 CFStringRef kMKBDeviceModeKey = CFSTR("kMKBDeviceModeKey");
533 static CFStringRef staticKeybagHandle = CFSTR("keybagHandle");
536 MKBKeyBagCreateWithData(CFDataRef keybagBlob, MKBKeyBagHandleRef* newHandle)
538 *newHandle = (MKBKeyBagHandleRef)staticKeybagHandle;
539 return kMobileKeyBagSuccess;
543 MKBKeyBagUnlock(MKBKeyBagHandleRef keybag, CFDataRef passcode)
545 if (keybag == NULL || !CFEqual(keybag, staticKeybagHandle)) {
548 return kMobileKeyBagSuccess;
551 int MKBKeyBagGetAKSHandle(MKBKeyBagHandleRef keybag, int32_t *handle)
553 if (keybag == NULL || !CFEqual(keybag, staticKeybagHandle)) {
557 return kMobileKeyBagSuccess;
560 int MKBGetDeviceLockState(CFDictionaryRef options)
562 if ([SecMockAKS isLocked:key_class_ak]) {
563 return kMobileKeyBagDeviceIsLocked;
565 return kMobileKeyBagDeviceIsUnlocked;
568 CF_RETURNS_RETAINED CFDictionaryRef
569 MKBUserTypeDeviceMode(CFDictionaryRef options, CFErrorRef * error)
571 return CFBridgingRetain(@{
572 (__bridge NSString *)kMKBDeviceModeKey : (__bridge NSString *)kMKBDeviceModeSingleUser,
576 int MKBForegroundUserSessionID( CFErrorRef * error)
578 return kMobileKeyBagSuccess;
581 const CFTypeRef kAKSKeyAcl = (CFTypeRef)CFSTR("kAKSKeyAcl");
582 const CFTypeRef kAKSKeyAclParamRequirePasscode = (CFTypeRef)CFSTR("kAKSKeyAclParamRequirePasscode");
584 const CFTypeRef kAKSKeyOpDefaultAcl = (CFTypeRef)CFSTR("kAKSKeyOpDefaultAcl");
585 const CFTypeRef kAKSKeyOpEncrypt = (CFTypeRef)CFSTR("kAKSKeyOpEncrypt");
586 const CFTypeRef kAKSKeyOpDecrypt = (CFTypeRef)CFSTR("kAKSKeyOpDecrypt");
587 const CFTypeRef kAKSKeyOpSync = (CFTypeRef)CFSTR("kAKSKeyOpSync");
588 const CFTypeRef kAKSKeyOpDelete = (CFTypeRef)CFSTR("kAKSKeyOpDelete");
589 const CFTypeRef kAKSKeyOpCreate = (CFTypeRef)CFSTR("kAKSKeyOpCreate");
590 const CFTypeRef kAKSKeyOpSign = (CFTypeRef)CFSTR("kAKSKeyOpSign");
591 const CFTypeRef kAKSKeyOpSetKeyClass = (CFTypeRef)CFSTR("kAKSKeyOpSetKeyClass");
592 const CFTypeRef kAKSKeyOpWrap = (CFTypeRef)CFSTR("kAKSKeyOpWrap");
593 const CFTypeRef kAKSKeyOpUnwrap = (CFTypeRef)CFSTR("kAKSKeyOpUnwrap");
594 const CFTypeRef kAKSKeyOpComputeKey = (CFTypeRef)CFSTR("kAKSKeyOpComputeKey");
595 const CFTypeRef kAKSKeyOpAttest = (CFTypeRef)CFSTR("kAKSKeyOpAttest");
596 const CFTypeRef kAKSKeyOpTranscrypt = (CFTypeRef)CFSTR("kAKSKeyOpTranscrypt");
597 const CFTypeRef kAKSKeyOpECIESEncrypt = (CFTypeRef)CFSTR("kAKSKeyOpECIESEncrypt");
598 const CFTypeRef kAKSKeyOpECIESDecrypt = (CFTypeRef)CFSTR("kAKSKeyOpECIESDecrypt");
599 const CFTypeRef kAKSKeyOpECIESTranscode = (CFTypeRef)CFSTR("kAKSKeyOpECIESTranscode");
602 TKTokenRef TKTokenCreate(CFDictionaryRef attributes, CFErrorRef *error)
607 CFTypeRef TKTokenCopyObjectData(TKTokenRef token, CFDataRef objectID, CFErrorRef *error)
612 CFDataRef TKTokenCreateOrUpdateObject(TKTokenRef token, CFDataRef objectID, CFMutableDictionaryRef attributes, CFErrorRef *error)
617 CFDataRef TKTokenCopyObjectAccessControl(TKTokenRef token, CFDataRef objectID, CFErrorRef *error)
621 bool TKTokenDeleteObject(TKTokenRef token, CFDataRef objectID, CFErrorRef *error)
626 CFDataRef TKTokenCopyPublicKeyData(TKTokenRef token, CFDataRef objectID, CFErrorRef *error)
631 CFTypeRef TKTokenCopyOperationResult(TKTokenRef token, CFDataRef objectID, CFIndex secKeyOperationType, CFArrayRef algorithm,
632 CFIndex secKeyOperationMode, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error)
637 CF_RETURNS_RETAINED CFDictionaryRef TKTokenControl(TKTokenRef token, CFDictionaryRef attributes, CFErrorRef *error)
642 CFTypeRef LACreateNewContextWithACMContext(CFDataRef acmContext, CFErrorRef *error)
647 CFDataRef LACopyACMContext(CFTypeRef context, CFErrorRef *error)
652 bool LAEvaluateAndUpdateACL(CFTypeRef context, CFDataRef acl, CFTypeRef operation, CFDictionaryRef hints, CFDataRef *updatedACL, CFErrorRef *error)
658 ACMContextCreateWithExternalForm(const void *externalForm, size_t dataLength)
664 ACMContextDelete(ACMContextRef context, bool destroyContext)
666 return kACMErrorSuccess;
670 ACMContextRemovePassphraseCredentialsByPurposeAndScope(const ACMContextRef context, ACMPassphrasePurpose purpose, ACMScope scope)
672 return kACMErrorSuccess;
675 #endif // TARGET_OS_BRIDGE