Keychain Services API fails with errSecNotAvailabl

2020-07-14 09:25发布

Calls to the the Keychain Services fail with errSecNotAvailable when executing a target using the command line tools and the iphone simulator is set to Hardware version 6.0 (10A403). If I change the simulator version to other previous version (4.3, 5.0, 5.1) and re-execute using the same command line script the calls succeed.

I'm running latest XCode 4.5 and the command line tools were downloaded from within XCode.

To reproduce this error just do the following:

  1. Setup an ios library project with a OCUnit target
  2. Set Base SDK to 6.0
  3. Set iOS Deployment Target to 4.3
  4. Copy and paste the code st the end of the post into the test project (it will only try to store a password and retrieve it)
  5. Add the Security.framework to the OCUnit target

Execute the OCUnit target in XCode and see the test pass with whatever Hardware Version is set in the iphone simulator (just change it between executions).

Execute the OCUnit target from the command line using:

xcodebuild -target TARGET_NAME_HERE -sdk iphonesimulator -configuration Release TEST_AFTER_BUILD=YES

with iphone simulator set to Hardware Version 6.0 and the test will fail. If you change the iphone simulator Hardware Version to 4.3, 5.0 or 5.1 and execute the command line script again the test will succeed.

Is this a command line tool problem? an iphone simulator problem? an OCUnit target running from the command line problem?

Who likes having unit tests that only pass when comets are aligned??

Any ideas?

Here is the code:

#define KEYCHAIN_ITEM_ATTRIBUTES (id)kSecClassGenericPassword, kSecClass, @"MyService", kSecAttrService, @"MyPassword", kSecAttrAccount

const NSString* MyPassword = @"blabla";

- (void)testExample
{
    // remove previous keychain item
    OSStatus status = SecItemDelete((CFTypeRef)[NSDictionary dictionaryWithObjectsAndKeys:KEYCHAIN_ITEM_ATTRIBUTES, nil]);
    NSLog(@"SecItemDelete status:%ld",status);
    NSParameterAssert(status == errSecSuccess || status == errSecItemNotFound);

    // add keychain item with new value
    NSData *data = [MyPassword dataUsingEncoding:NSUTF8StringEncoding];
    status = SecItemAdd((CFTypeRef)[NSDictionary dictionaryWithObjectsAndKeys:KEYCHAIN_ITEM_ATTRIBUTES, data, kSecValueData, nil], NULL);
    NSLog(@"SecItemAdd status:%ld",status);
    NSParameterAssert(status == errSecSuccess);

    // get password
    status = SecItemCopyMatching((CFTypeRef)[NSDictionary dictionaryWithObjectsAndKeys:KEYCHAIN_ITEM_ATTRIBUTES,
                                             kSecMatchLimitOne, kSecMatchLimit, kCFBooleanTrue, kSecReturnData, nil], (CFTypeRef *)&data);
    NSLog(@"SecItemCopyMatching status:%ld",status);
    NSParameterAssert(status == errSecSuccess);

    if (status == errSecItemNotFound)
        NSLog(@"SecItemCopyMatching status:%ld", status);
    else
        NSLog(@"SecItemCopyMatching result:%@",[[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]);
}

Regarding securityd daemon not being launched, I can check it IS being launched, using

launchctl list | grep securityd

after the simulator starts, and getting

-   0   com.apple.iPhoneSimulator:com.apple.securityd

I also tried stopping this securityd daemon and launch another manually... I looked at GTM's RunIPhoneUnitTest.sh script for a simple line I could use, but when I try this

launchctl submit -l ios6securityd -- /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator6.0.sdk/usr/libexec/securityd

gives me a -5 status code on that daemon.

1条回答
家丑人穷心不美
2楼-- · 2020-07-14 09:35

I came across this because I was having trouble getting keychain access when trying to run my unit tests from the Xcode 4.5.1 UI. Luckily, the breakage is something I'm familiar with from CI builds with most previous Xcode versions as well, which is that the simulator's securityd isn't properly launched.

Try launching securityd first, and see if that helps:

#!/bin/bash

simulator_root=`xcodebuild -version -sdk iphonesimulator Path`
"${simulator_root}/usr/libexec/securityd"

That worked for me.

查看更多
登录 后发表回答