NSURLCredentialStorage 和客户端证书认证

发布于 2024-10-01 19:00:25 字数 2831 浏览 4 评论 0原文

从我在 MPMoviewPlayerController 的文档中看到的,NSURLCredentialStorage 可以设置为 NSURLConnection 身份验证挑战的替代方案(这对于从 URL 加载资源但抽象 NSURLConnection 且不提供处理身份验证的委托的高级类很有用)挑战)。这看起来类似于在浏览器中安装证书并在某个地址需要时自动选择所需的证书。

为了测试这一点,我设置了自己的证书颁发机构、服务器证书和客户端证书(.p12 文件)。我已经设置了一个 https 服务器,并使用浏览器从一台单独的计算机成功测试了客户端证书。

现在我需要将证书集成到我的 iPhone 应用程序中。

我已经捆绑了 p12 文件,并在应用程序启动时执行以下操作:

NSString *thePath = [[NSBundle mainBundle] pathForResource:@"clientside" ofType:@"p12"];
NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath];
CFDataRef inPKCS12Data = (CFDataRef)PKCS12Data;    
SecIdentityRef identity;
SecTrustRef trust;
extractIdentityAndTrust(inPKCS12Data, &identity, &trust);

SecCertificateRef certificate = NULL;
SecIdentityCopyCertificate (identity, &certificate); 

const void *certs[] = {certificate};
CFArrayRef certArray = CFArrayCreate(kCFAllocatorDefault, certs, 1, NULL);

NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identity certificates:(NSArray*)certArray persistence:NSURLCredentialPersistencePermanent];

NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc]
                                         initWithHost: @"myhostname"
                                         port: 443
                                         protocol: @"https"
                                         realm: nil
                                         authenticationMethod: NSURLAuthenticationMethodClientCertificate];

[[NSURLCredentialStorage sharedCredentialStorage]
 setDefaultCredential: credential
 forProtectionSpace: protectionSpace];

extractIdentityAndTrust 函数只是从“iOS 的证书、密钥和信任服务任务”文档页面复制而来(我只是用自己的密码替换了证书密码)。

据我所知,身份和证书加载得很好。如果我在控制台中打印 NSURLCredential 对象,我会得到如下内容: : (null) (我无法判断这是否是一个好兆头)。

但是,当我执行 setDefaultCredential 时,应用程序崩溃而没有提供太多信息。

堆栈跟踪看起来像这样:

#0  0x350a41c8 in CFHash
#1  0x3515180c in __CFBasicHashStandardHashKey
#2  0x351534e4 in ___CFBasicHashFindBucket_Linear
#3  0x350a4000 in CFBasicHashFindBucket
#4  0x350a3ecc in CFDictionaryGetValue
#5  0x344a0df2 in URLCredentialStorage::setDefaultCredentialForProtectionSpace
#6  0x3446a5aa in CFURLCredentialStorageSetDefaultCredentialForProtectionSpace
#7  0x339ec79e in -[NSURLCredentialStorage setDefaultCredential:forProtectionSpace:]
#8  0x00002612 in -[AVPlayerExampleViewController awakeFromNib] at AVPlayerExampleViewController.m:84

在我看来,凭证中没有设置某些内容。

关于如何解决这个问题有什么想法吗?

编辑:

只是为了测试,我通过从邮件打开文件在 iPhone 上安装了证书。我可以通过 Safari 通过 https 访问页面,但不能通过我的应用程序访问。

唯一有效的是,如果我打开一个 NSURLConnection 到受保护域上的任何资源,响应 didReceiveAuthenticationChallenge (我加载我的凭据与上面的代码完全相同,只是我将其直接发送到 NSURLAuthenticationChallenge 的发件人),然后访问这些内容我真的需要使用更高级别的课程。

From what I see in the documentation of MPMoviewPlayerController, NSURLCredentialStorage can be set up as an alternative of NSURLConnection authentication challenges (this is useful for higher level classes that load resources from URLs but abstract the NSURLConnection away and don't provide a delegate for handling authentication challenges). This seems similar to installing a certificate in the browser and having it auto select the required certificate when a certain address demands it.

To test this out I have set up my own certificate authority, server certificate and client certificate (a .p12 file). I've set up an https server and successfully tested the client certificate using a browser, from a separate machine.

Now I need to have the certificate integrated in my iPhone app.

I've bundled up the p12 file and on application launch I do this:

NSString *thePath = [[NSBundle mainBundle] pathForResource:@"clientside" ofType:@"p12"];
NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath];
CFDataRef inPKCS12Data = (CFDataRef)PKCS12Data;    
SecIdentityRef identity;
SecTrustRef trust;
extractIdentityAndTrust(inPKCS12Data, &identity, &trust);

SecCertificateRef certificate = NULL;
SecIdentityCopyCertificate (identity, &certificate); 

const void *certs[] = {certificate};
CFArrayRef certArray = CFArrayCreate(kCFAllocatorDefault, certs, 1, NULL);

NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identity certificates:(NSArray*)certArray persistence:NSURLCredentialPersistencePermanent];

NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc]
                                         initWithHost: @"myhostname"
                                         port: 443
                                         protocol: @"https"
                                         realm: nil
                                         authenticationMethod: NSURLAuthenticationMethodClientCertificate];

[[NSURLCredentialStorage sharedCredentialStorage]
 setDefaultCredential: credential
 forProtectionSpace: protectionSpace];

The extractIdentityAndTrust function is simply copied form the 'Certificate, Key, and Trust Services Tasks for iOS' documentation page (I just replaced the certificate password with my own).

From what I can tell the identity and the certificate are loaded nicely. If I print the NSURLCredential object in the console I get something like this: <NSURLCredential: 0x140ea0>: (null) (I can't tell if this is a good sign or not).

However when I execute setDefaultCredential the app crashes without giving much information.

The stacktrace looks something like this:

#0  0x350a41c8 in CFHash
#1  0x3515180c in __CFBasicHashStandardHashKey
#2  0x351534e4 in ___CFBasicHashFindBucket_Linear
#3  0x350a4000 in CFBasicHashFindBucket
#4  0x350a3ecc in CFDictionaryGetValue
#5  0x344a0df2 in URLCredentialStorage::setDefaultCredentialForProtectionSpace
#6  0x3446a5aa in CFURLCredentialStorageSetDefaultCredentialForProtectionSpace
#7  0x339ec79e in -[NSURLCredentialStorage setDefaultCredential:forProtectionSpace:]
#8  0x00002612 in -[AVPlayerExampleViewController awakeFromNib] at AVPlayerExampleViewController.m:84

Looks to me like there something not set up in the credential.

Any ideas on how to solve this?

EDIT:

Just for testing I installed the certificate on the iPhone by opening the file from Mail. I can access the pages over https through Safari, but not through my app.

The only thing that works is if I open an NSURLConnection to any resource on the protected domain, respond to didReceiveAuthenticationChallenge (where I load up my credential exactly like in the code above, only I send it directly to NSURLAuthenticationChallenge's sender) and then access the stuff I really need using the higher level class.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

酷到爆炸 2024-10-08 19:00:25

NSURLCredentialStorage 仅适用于用户名和用户名似乎是一个已知问题。密码 NSURLCredentials(不支持证书)。不幸的是,文档没有提到这一点。

It seems it's a known issue that NSURLCredentialStorage only works for username & password NSURLCredentials (certificates are not supported). Unfortunately the documentation mentions nothing about this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文