我正在尝试从iOS中的各种URL读取证书。但是我的代码运行不正常 - 应该返回我需要的信息的数组总是返回null
。
我错过了什么?
- (void)findCertificate:(NSString *)url
{
NSInputStream*input = [[NSInputStream inputStreamWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"https://store.writeitstudios.com"]]] retain];
[input setDelegate:self];
[input scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[input open];
NSLog(@"Status: %i",[input streamStatus]);
}
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
NSLog(@"handle Event: %i",eventCode);
if (eventCode == NSStreamStatusOpen)
{
NSArray *certificates = (NSArray*)CFReadStreamCopyProperty((CFReadStreamRef)aStream, kCFStreamPropertySSLPeerCertificates);
NSLog(@"Certs: %@",CFReadStreamCopyProperty((CFReadStreamRef)aStream, kCFStreamPropertySSLPeerCertificates));
if ([certificates count] > 0) {
SecCertificateRef certificate = (SecCertificateRef)[certificates objectAtIndex:0];
NSString *description = (NSString*)SecCertificateCopySubjectSummary(certificate);
NSData *data = (NSData *)SecCertificateCopyData(certificate);
NSLog(@"Description: %@",description);
}
}
}
是的,我知道我在泄漏记忆。这只是一个片段。
答案 0 :(得分:9)
让我解释一下你在这里做了什么以及为什么这是错误的:
NSData
(数据缓冲区)中。请注意,您不加载任何证书(从技术上讲,NSURL
会在内部加载它们,但此代码绝对不会将它们放入NSData
)NSStream
的委托方法stream:handleEvent:
,并且正在尝试读取kCFStreamPropertySSLPeerCertificates属性。此属性将为空,因为流只包含一些HTML数据,没有别的。NSArray
。NULL
。对于手头的任务,不需要使用NSStream
/ CFStream
。绝大多数情况下,您不必首先通过NSURLConnection
,然后通过NSStream
。
要检索SSL服务器证书,请坚持使用简单的异步NSURLConnection
并使用其委托方法访问证书:
// Method to begin the asynchronous download
- (void)beginCertificateDownload:(NSURL *)url
{
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
}
// NSURLConnection Delegate Methods
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{
return [[protectionSpace authenticationMethod] isEqualToString:NSURLAuthenticationMethodServerTrust];
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
// extract the certificates
SecTrustRef trustRef = [[challenge protectionSpace] serverTrust];
CFIndex count = SecTrustGetCertificateCount(trustRef);
for (CFIndex i = 0; i < count; i++) {
SecCertificateRef certRef = SecTrustGetCertificateAtIndex(trustRef, i);
CFStringRef certSummary = SecCertificateCopySubjectSummary(certRef);
NSLog(@"%@", certSummary);
// do whatever you need with the certificates here
// don't forget to copy them if you need to keep them
// around beyond the scope of this method
}
// I'm assuming you're not interested in actually loading the contents of the URL, so cancel
[[challenge sender] cancelAuthenticationChallenge:challenge];
// you'll also want to release the connection object at some point
}