OSX: Export system certificates from keychain in PEM format programmatically
Asked Answered
X

3

10

How can I extract all root CA certificates from all the keychains on OSX programmatically in pem format?

Keychain programming services should allow this but how?

Any help would be appreciable.

Xerosis answered 9/9, 2015 at 6:28 Comment(0)
K
11
security find-certificate -a -p /System/Library/Keychains/SystemRootCertificates.keychain >certs-roots.pem
security find-certificate -a -p /Library/Keychains/System.keychain >certs-system.pem
security find-certificate -a -p ~/Library/Keychains/login.keychain-db >certs-user.pem

BTW: You can see those paths in Keychain Access when you hover over the Keychains list (top/left).

You can combine system and user pems by using the default certificate source

security find-certificate -a -p >certs.pem

This is super useful for node.js, when you want to use require('https').request on typical corporate internal stuff without having to resort to hacks like accepting any certificate without checking. You don't need to include the system roots since nodejs has you covered already for those.

NODE_EXTRA_CA_CERTS=certs.pem node
Kittykitwe answered 19/3, 2019 at 20:18 Comment(0)
X
4

Answering my own question: On OSX you can invoke a NSTask to get response from the security command line utility:

security find-certificate -a -p /System/Library/Keychains/SystemCACertificates.keychain > allcerts.pem
Xerosis answered 10/9, 2015 at 3:56 Comment(0)
B
4

Hey I know I'm late to this but I came across the same problem today and spent many hours figuring out how to do this. I know that the original poster might not need to know this anymore but hopefully this helps someone.

The following is my code to exactly replicate what you've done without using the command line.

+ (NSURL *)createCertsFileInDirectory:(NSURL *)directory {
    NSString *outPath = [directory path];
    if (!outPath) {
        return nil;
    }
    outPath = [outPath stringByAppendingPathComponent:@"allcerts.pem"];
    NSURL * outURL = [NSURL fileURLWithPath:outPath];
    SecKeychainRef keychain;
    if (SecKeychainOpen("/System/Library/Keychains/SystemCACertificates.keychain", &keychain) != errSecSuccess) {
        return nil;
    }
    CFMutableArrayRef searchList = CFArrayCreateMutable(kCFAllocatorDefault, 1, &kCFTypeArrayCallBacks);
    CFArrayAppendValue(searchList, keychain);
    CFTypeRef keys[] = { kSecClass, kSecMatchLimit, kSecAttrCanVerify, kSecMatchSearchList };
    CFTypeRef values[] = { kSecClassCertificate, kSecMatchLimitAll, kCFBooleanTrue, searchList };
    CFDictionaryRef dict = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    CFTypeRef results;
    OSStatus status = SecItemCopyMatching(dict, &results);
    CFArrayRef arr = (CFArrayRef) results;
    NSLog(@"total item count = %ld", CFArrayGetCount(arr));
    CFRelease(dict);
    CFRelease(searchList);
    CFRelease(keychain);
    if (status != errSecSuccess) {
        return nil;
    }
    CFDataRef certsData;
    status = SecItemExport(results, kSecFormatPEMSequence, kSecItemPemArmour, NULL, &certsData);
    CFRelease(results);
    if (status != errSecSuccess) {
        return nil;
    }
    NSData *topLevelData = (NSData *) CFBridgingRelease(certsData);
    if (![topLevelData writeToURL:outURL atomically:YES]) {
        return nil;
    }
    return outURL;
}
Blown answered 16/4, 2016 at 1:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.