Using NSFileManager's getFileProviderServicesForItemAtURL method, I can list services made available by a file provider for a given item from an app unrelated to the file provider, obtain a handle to the proxy object and cast that object to the target protocol. However, attempts to invoke the protocol yield:
"The connection to service named com.apple.mobile.usermanagerd.xpc was invalidated: failed at lookup with error 159 - Sandbox restriction."
The documentation for the supportedServiceSourcesForItemIdentifier method implemented by the extension suggests only the app containing the extension can exercise the service but the documentation for getFileProviderServicesForItemAtURL does not. Should I be able to access a service from a file provider extension from an unrelated app? If so, how can the sandbox restriction be addressed?
Post
Replies
Boosts
Views
Activity
Is it possible to restrict access to a persistent token extension, i.e. to block use of keys hosted by a managed app from an unmanaged app? Something like the allowOpenFromManagedToUnmanaged/allowOpenFromUnmanagedToManaged pair is what I was looking for.
When I generate or import keys with kSecAccessControlUserPresence, SecItemCopyMatching fails about a quarter of the time with errSecAuthFailed. Generation is like this:
SecKeyRef publicKey = NULL;
SecKeyRef privateKey = NULL;
SecAccessControlRef access =
		SecAccessControlCreateWithFlags(kCFAllocatorDefault,
																		kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
																		kSecAccessControlUserPresence,
																		nil);
NSMutableDictionary* privateKeyAttr = [[NSMutableDictionary alloc] init];
[privateKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecAttrIsPermanent];
[privateKeyAttr setObject:(id)label forKey:(id)kSecAttrApplicationTag];
[privateKeyAttr setObject:(__bridge id)access forKey:(id)kSecAttrAccessControl];
NSMutableDictionary* publicKeyAttr = [[NSMutableDictionary alloc] init];
[publicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecAttrIsPermanent];
[publicKeyAttr setObject:(id)label forKey:(id)kSecAttrApplicationTag];
NSMutableDictionary* keyPairAttr = [[NSMutableDictionary alloc] init];
[keyPairAttr setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType];
[keyPairAttr setObject:[NSNumber numberWithInt:2048] forKey:(id)kSecAttrKeySizeInBits];
[keyPairAttr setObject:privateKeyAttr forKey:(id)kSecPrivateKeyAttrs];
[keyPairAttr setObject:publicKeyAttr forKey:(id)kSecPublicKeyAttrs];
OSStatus status = SecKeyGeneratePair((CFDictionaryRef)keyPairAttr, &publicKey, &privateKey);
SecItemCopyMatching is invoked like this:
NSMutableDictionary * query = [[NSMutableDictionary alloc] init];
[query setObject:(id)kSecMatchLimitAll forKey:(id)kSecMatchLimit];
[query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnRef];
[query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
[query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnAttributes];
[query setObject:(id)label forKey:(id)kSecAttrApplicationTag];
[query setObject:(id)kSecClassKey forKey:(id)kSecClass];
CFTypeRef result = nil;
OSStatus status = SecItemCopyMatching((CFDictionaryRef)query, &result);
Any thoughts on how to reliably invoke SecItemCopyMatching in this case?
When I add a password to the keychain as follows:
SecAccessControlRef sacObject = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
kSecAccessControlUserPresence, &error);
NSDictionary *attributes = @{
(bridge id)kSecClass: (bridge id)kSecClassGenericPassword,
(__bridge id)kSecValueData: [@"password" dataUsingEncoding:NSUTF8StringEncoding],
(__bridge id)kSecAttrLabel: @"passwordWithACL",
(__bridge id)kSecUseNoAuthenticationUI: @YES,
(bridge id)kSecAttrAccessControl: (bridge_transfer id)sacObject
};
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)attributes, nil);
attempts to access via SecItemCopyMatching as below work fine. The user is prompted to enter device PIN and errSecSuccess is returned.
NSDictionary *attributes2 = @{
(bridge id)kSecClass: (bridge id)kSecClassGenericPassword,
(__bridge id)kSecReturnData: @YES,
(__bridge id)kSecUseOperationPrompt: @"Authenticate",
(__bridge id)kSecAttrLabel: @"passwordWithACL",
};
CFTypeRef dataTypeRef = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)(attributes2), &dataTypeRef);
When I add an identity using this similar code:
SecAccessControlRef access =
SecAccessControlCreateWithFlags(kCFAllocatorDefault,
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
kSecAccessControlUserPresence,
nil);
NSMutableDictionary* dict = [[NSMutableDictionary alloc]init];
[dict setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnPersistentRef];
[dict setObject:(__bridge id)identity forKey:(id)kSecValueRef];
[dict setObject:@"identityWithACL" forKey:(id)kSecAttrLabel];
[dict setObject:(__bridge id)access forKey:(id)kSecAttrAccessControl];
CFTypeRef persistent_ref;
OSStatus status = SecItemAdd((CFDictionaryRef)dict, &persistent_ref);
attempts to access via SecItemCopyMatching as below fails. The user is prompted to enter device PIN and errSecItemNotFound is returned.
NSMutableDictionary * query = [[NSMutableDictionary alloc] init];
[query setObject:(id)kSecClassIdentity forKey:(id)kSecClass];
[query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnRef];
[query setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
[query setObject:@"Authenticate to access identity" forKey:(id)kSecUseOperationPrompt];
[query setObject:@"identityWithACL" forKey:(id)kSecAttrLabel];
CFTypeRef items = nil;
OSStatus status = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef *)&items);
When I replace the kSecAttrAccessControl item in the dictionary passed SecItemAdd with the below, I can access the identity with no issue.
[dict setObject:(id)kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly forKey:(id)kSecAttrAccessible];
What's the trick for adding identities with user presence required for access?