Search code examples
iphoneiosxcodeclient-certificatespkcs#12

Importing a client certificate into the iPhone's keychain


I am writing an application that is communicating with a server which requires the client to authenticate itself using a client certificate. I need to extract the certificate from a .p12 file in the application bundle and add it to the application keychain.

I've been trying to figure out how to get it working from Apple's "Certificate, Key, and Trust Services Tasks for iOS", but to me it seems incomplete and does not specify how I add anything to the keychain(?).

I am quite lost and any help is appriciated, thanks in advance!


Solution

  • "Certificate, Key, and Trust Services Tasks for iOS" does contain sufficient information to extract certificate from a .p12 file.

    • from listing 2-1 demonstrate how you can extract SecIdentityRef

    • from listing 2-2 second line (// 1) shows how you can copy SecCertificateRef out of SecIdentityRef.

    example loading p12 file, extract certificate, install to keychain. (error handling and memory management was not included)

      NSString * password = @"Your-P12-File-Password";
      NSString * path = [[NSBundle mainBundle]
                         pathForResource:@"Your-P12-File" ofType:@"p12"];
    
      // prepare password
      CFStringRef cfPassword = CFStringCreateWithCString(NULL,
                                                         password.UTF8String,
                                                         kCFStringEncodingUTF8);
      const void *keys[]   = { kSecImportExportPassphrase };
      const void *values[] = { cfPassword };
      CFDictionaryRef optionsDictionary
      = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 1,
                                                      NULL, NULL);
    
      // prepare p12 file content
      NSData * fileContent = [[NSData alloc] initWithContentsOfFile:path];
      CFDataRef cfDataOfFileContent = (__bridge CFDataRef)fileContent;
    
      // extract p12 file content into items (array)
      CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
      OSStatus status = errSecSuccess;
      status = SecPKCS12Import(cfDataOfFileContent,
                               optionsDictionary,
                               &items);
      // TODO: error handling on status
    
      // extract identity
      CFDictionaryRef yourIdentityAndTrust = CFArrayGetValueAtIndex(items, 0);
      const void *tempIdentity = NULL;
      tempIdentity = CFDictionaryGetValue(yourIdentityAndTrust,
                                          kSecImportItemIdentity);
    
      SecIdentityRef yourIdentity = (SecIdentityRef)tempIdentity;
    
    
      // get certificate from identity
      SecCertificateRef yourCertificate = NULL;
      status = SecIdentityCopyCertificate(yourIdentity, &yourCertificate);
    
    
      // at last, install certificate into keychain
      const void *keys2[]   = {    kSecValueRef,             kSecClass };
      const void *values2[] = { yourCertificate,  kSecClassCertificate };
      CFDictionaryRef dict
      = CFDictionaryCreate(kCFAllocatorDefault, keys2, values2,
                                                2, NULL, NULL);
      status = SecItemAdd(dict, NULL);
    
      // TODO: error handling on status