Retrieve trusted certificates from Apple's Keychain in C

Hi,

I'm trying to retrieve trusted certificates from the Apple's Keychain using plain C API.

From reading some articles, my understanding is that

  • Apple has C API to access Apple's Keychain
  • Apple provides Objective-C and Swift wrappers for the C API

I see that the documentation for Objective C and Swift: https://developer.apple.com/documentation/security/keychain_services?language=objc

Could somebody help me figure out the followings?

Q1. Is there a C API available?

Q2. Where can I find the header files?

Q3. Which libraries do I need to link my program to?

Thanks in advance!

Accepted Answer

I see that the documentation for Objective-C and Swift

If you look at the API that this links to, you’ll see it’s implemented as a set of C functions (SecItemCopyMatching, SecItemApp, SecItemUpdate, and SecItemDelete). You can call these from Swift and any C-based language (C, Objective-C, C++, Objective-C++).

Q1. Is there a C API available?

Yes.

Q2. Where can I find the header files?

In the Security framework.

Q3. Which libraries do I need to link my program to?

The Security framework.

For example, if you create a new C project from Xcode’s macOS > Command Line Tool target, the following code will print all the keys in your macOS keychain:

#include <Security/Security.h>

int main(int argc, const char * argv[]) {
    CFStringRef keys[] = { kSecClass,    kSecMatchLimit,    kSecReturnRef };
    CFTypeRef values[] = { kSecClassKey, kSecMatchLimitAll, kCFBooleanTrue };
    CFDictionaryRef query = CFDictionaryCreate(
        NULL,
        (const void **) keys,
        values,
        sizeof(keys) / sizeof(keys[0]),
        &kCFTypeDictionaryKeyCallBacks,
        &kCFTypeDictionaryValueCallBacks
    );
    CFTypeRef copyResult = NULL;
    OSStatus err = SecItemCopyMatching(query, &copyResult);
    if (err == errSecSuccess) {
        CFShow(copyResult);
    }
    return 0;
}

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Q1. Is there a tar file of the Security framework tool kit (e.g. header files, libraries, etc)?

No. To build for iOS you need an iOS SDK. This includes all the frameworks, non-framework headers, non-framework stub libraries, and so on. It’s included with Xcode but there’s nothing to stop you from using it with a third-party build system, like make.

Note If you’re unfamiliar with the concept of stub libraries, see this post.

Q2. I'm linux/unix developer

Yes, it shows (-:

and I'm not familiar with iOS development. It looks like iOS libraries have the .dylib file extension.

To be clear, iOS shared libraries use the .dylib extension but iOS frameworks, which is what you need here, use the .framework extension. A framework is a package (a directory that’s meant to be treated as a single file) that’s structured in one of two ways:

  • For development, a framework contains headers and a stub library (.tbd).

  • At runtime, a framework contains a dynamic library and any associated resources.

Note that in the second case the dynamic library does not have the .dylib extension.

Which library do I need to link my program to use the Security framework functions?

I’m happy to answer focused questions but this speaks to the whole issue of how you build an iOS app from scratch, which is way more complex than I can explain here. My advice is that you create a tiny test project in Xcode and build it for an iOS device. Then look at the build transcript to see how Xcode does this job, and then mirror it in your third-party build systems.

To get a build transcript, use the Report navigation. See Xcode Help > Debug code > View and filter logs and reports.

However, just to make sure you start off on the right path:

  • Focus on the -isysroot argument. This is how you tell clang about the SDK you want to use, and it will find system frameworks, like the Security framework, from there.

  • Xcode uses the clang driver for both compiling and linking, and I encourage you to do the same. It’s possible to invoke ld directly, but it’s better to follow Xcode’s lead and do everything with clang.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I meant to ask for MacOS, and not for iOS.

That doesn’t change things. We used an SDK-based development process for all our platforms. That’s what allows folks to, for example, develop code for macOS 12 while running on macOS 11.

Did you read the other post I linked to? This explains the backstory here.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Retrieve trusted certificates from Apple's Keychain in C
 
 
Q