阅读iOS问题证书

时间:2011-06-22 09:23:25

标签: iphone objective-c certificate

我正在尝试从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);
        }
    }
}

是的,我知道我在泄漏记忆。这只是一个片段。

1 个答案:

答案 0 :(得分:9)

让我解释一下你在这里做了什么以及为什么这是错误的:

  1. 您正在将https://store.writeitstudios.com(即HTML)的内容同步加载到NSData(数据缓冲区)中。请注意,您加载任何证书(从技术上讲,NSURL会在内部加载它们,但此代码绝对不会将它们放入NSData
  2. 您正在打开输入流并将数据(一点HTML,没有证书!)粘贴到其中。
  3. 您已经实现了NSStream的委托方法stream:handleEvent:,并且正在尝试读取kCFStreamPropertySSLPeerCertificates属性。此属性将为空,因为流只包含一些HTML数据,没有别的。
  4. 您正在将空属性转换为NSArray
  5. 循环未执行,因为数组为NULL
  6. 对于手头的任务,不需要使用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
    }