iPhone应用程序与SSL客户端证书

20
我正在开发一个需要使用客户端证书通过https访问web服务的iPhone应用程序。如果我将客户端证书(以pkcs12格式)放入应用程序包中,我就能够将其加载到应用程序中并进行https调用(这在很大程度上得益于stackoverflow.com)。
但是,我需要一种方法来分发应用程序而不需要任何证书,并留给用户提供自己的证书。我认为我只需指示用户在iPhone的配置文件(设置->通用->配置文件)中导入证书,这是通过在Mail.app中打开.p12文件时获得的内容,然后我将在我的应用程序中访问该项。我希望配置文件中的证书可以通过密钥串API获取,但我想我错了。
1)有没有办法在我的应用程序中访问我已经加载到iPhone配置文件中的证书?
2)我还有哪些其他选项来加载用户指定的证书到我的应用程序中?我所能想到的唯一的事情是提供一些接口,让用户提供他的.p12 cerificate的URL,然后我可以将其加载到应用程序的密钥串中供以后使用,但那不是很友好的用户界面。我正在寻找一些允许用户将证书放在手机上(将其发送电子邮件给自己),然后在我的应用程序中加载它的东西。

请问您能告诉我如何将 .p12 文件加载到应用程序中吗?我需要提取客户端证书的公钥。谢谢。 - Pablo A.
2
我联系了一位苹果安全框架的倡导者,他确认了这里已经说过的内容 - 在设置->通用->配置文件中加载的证书只能被内置应用程序(邮件、Safari)使用。你的应用程序只能使用存储在其钥匙串中的内容(或共享相同签名证书的其他第三方应用程序的钥匙串)。至于实际加载,我构建了一个与证书捆绑在一起的应用程序(仅供测试)。我从我的应用程序包中读取.p12,并使用SecPKCS12Import获取身份。然后,您可以使用它来使用SecIdentityCopyPrivateKey获取私钥。 - Pavel Georgiev
1
我已尝试使用以下代码:NSString *thePath = [[NSBundle mainBundle] pathForResource:@"certificate" ofType:@"p12"]; NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath]; CFDataRef inPKCS12Data = (CFDataRef)PKCS12Data;CFStringRef password = CFSTR("pass"); const void *keys[] = { kSecImportExportPassphrase }; const void *values[] = { password }; CFDictionaryRef optionsDictionary = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL); CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL); SecPKCS12Import(inPKCS12Data, optionsDictionary, &items);items为空。发生了什么? - Pablo A.
这个还适用吗?只有内置应用程序才能读取iPhone钥匙串中的证书吗?Junos Pulse VPN客户端在其应用程序配置中提供了已安装在系统钥匙串中的证书列表...我认为它不能被归类为内置应用程序...它是如何读取系统钥匙串的呢? - Nirmal Patel
@PabloAlejandro,你解决了你的问题吗?我也遇到了同样的问题:( - vikas
显示剩余2条评论
7个回答

3
我尝试了以下方法:
NSString *thePath = [[NSBundle mainBundle] pathForResource:@"certificate" ofType:@"p12"]; 
NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath]; 
CFDataRef inPKCS12Data = (CFDataRef)PKCS12Data; 
CFStringRef password = CFSTR("pass"); 
const void *keys[] = { kSecImportExportPassphrase }; 
const void *values[] = { password }; 
CFDictionaryRef optionsDictionary = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL); 
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL); 
SecPKCS12Import(inPKCS12Data, optionsDictionary, &items); 

inPKCS12Data是正确的,但items为空。发生了什么?


同样的代码在我这里能够运行。SecPKCS12Import会返回一个OSStatus状态码,获取该状态码来查看错误信息。 - Pavel Georgiev
我在4.3.2模拟器上遇到了同样的问题。但是在iOS SDK 5.0 beta6中的模拟器上可以工作。不知道其他版本如何。 - romrom
另一个可能为空的原因是:如果是自签名证书,则证书的到期日期太远。 - Cathy

2
我最近为一款应用程序实现了这种功能,即通过 iTunes 让应用程序的文档文件夹可访问。我们的用户随后会被指示将生成的 p12 格式密钥文件拖到 iTunes 中我们应用程序的文档面板中。当启动应用程序时,它会检查 p12 文件是否存在,并且如果存在,则会将该文件导入到密钥链中。虽然这不是最简单的过程,但是它是最安全的方式,因为您不需要通过电子邮件发送私钥文件。请注意保留 HTML 标签。

1

如果.p12文件不太大,您可以使用Base64进行编码,然后在电子邮件中嵌入一个带有自定义URL方案的链接,例如:

myapp://certificate/<base 64 data>

用户点击链接后,您的应用程序将证书保存在某个地方以备将来使用。只需确保 iPhone 上的 Mail.app 不会损坏电子邮件即可。

这背后有一个原因,我可能会尝试一下,但即使它有效,用户仍需要将证书编码为Base64并制作这封电子邮件,这不是很用户友好的。 - Pavel Georgiev
想一想,让Mail.app起作用的最简单方法是发送HTML电子邮件并使用A标签来添加链接。 - Sam Doshi
1
你能否为他们提供一个应用程序或网站来完成这个任务? - Sam Doshi

1
如果您正在使用AirWatch进行应用程序分发,他们的SDK提供了将证书从您的证书颁发机构预配到您的注册设备的功能。这使您可以预配您的证书,然后从您的应用程序代码中访问它们。

你有一个访问证书的代码片段吗? - Gabriel Diaconescu
是的,一个在Airwatch上适用的代码片段确实会很有帮助。谢谢! - archeopetrix

1

苹果确实限制了设备全局密钥/证书的使用,仅供其自己的应用程序/服务,如WiFi、VPN、邮件等使用。第三方应用程序无法使用这些密钥/证书(未越狱)。但是,应用程序可以在应用内键链中导入、存储和使用密钥和证书。此外,您可以使用iOS中的keychain-access-group功能在多个应用程序之间共享密钥/证书。

我最近发布了一篇名为In-App Mobile Certificates Made Easy with mCMS的博客文章,可能会对您有所帮助。我们公司正在开发一个API,使支持应用内证书变得容易,并直接从基于Microsoft的PKI获取它们。我们的解决方案也提供了设备上的密钥生成,而不是在另一台机器上生成P12并尝试将其导入到您的应用程序中。


0

哦,天啊,这让我想起了2009年10月/11月的痛苦回忆。我成功地使客户端证书正常工作,但我不得不把libcurl移植到iPhone上(因为当时NDA仍然有效),这并不容易。

我已经一年多没有做iPhone应用程序开发了,所以我不知道有多少变化,但如果我是你,我会首先尝试在没有客户端证书的情况下运行应用程序,如果你绝对需要使用它们,你可以使用带有PEM格式证书的libcurl。


0

不,我尝试使用kSecClassIdentity、kSecClassCertificate和kSecClassKey等值搜索kSecClass密钥,但始终得到空结果。然后我继续阅读,发现iPhone的钥匙串是每个应用程序独立的,也就是说,您只能访问您放入其中的内容,只有您的应用程序(以及使用相同AppID的签名证书的其他应用程序)才能访问该钥匙串。 - Pavel Georgiev
好的,那么回答你的第二个问题 - 除了指定一个URL并下载文件之外,没有API或AppStore可批准的方式将文件加载到iPhone中... - Adam Woś

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接