将客户端证书导入iPhone的密钥链

时间:2021-06-27 07:33:45

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.

我正在编写一个正在与服务器通信的应用程序,该服务器要求客户端使用客户端证书对自己进行身份验证。我需要从应用程序包中的.p12文件中提取证书,并将其添加到应用程序密钥链中。

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(?).

我一直在试图弄清楚如何从苹果的“iOS证书、密钥和信任服务任务”中让它工作,但对我来说,它似乎不完整,而且没有指定如何向keychain(?)添加任何内容。

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

我很失落,任何帮助都被告知,提前谢谢!

1 个解决方案

#1


4  

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

“iOS的证书、密钥和信任服务任务”包含足够的信息从.p12文件中提取证书。

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

    从清单2-1演示如何提取SecIdentityRef

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

    从清单2-2第二行(/ 1)可以看到如何从SecIdentityRef复制SecCertificateRef。

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

示例加载p12文件,提取证书,安装到keychain。(不包括错误处理和内存管理)

  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

#1


4  

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

“iOS的证书、密钥和信任服务任务”包含足够的信息从.p12文件中提取证书。

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

    从清单2-1演示如何提取SecIdentityRef

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

    从清单2-2第二行(/ 1)可以看到如何从SecIdentityRef复制SecCertificateRef。

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

示例加载p12文件,提取证书,安装到keychain。(不包括错误处理和内存管理)

  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