Reading Certificates on iOS Problem
I am trying to read certificates from various URLs in iOS. My code however is not working well - the array that should return the information I need always returns null
.
What am I missing?
- (void)findCertificate:(NSStri开发者_StackOverflowng *)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);
}
}
}
And yes, I am aware that I am leaking memory. This is just a snippet.
Let me explain what you're doing here and why it's wrong:
- You are loading the contents of the URL https://store.writeitstudios.com (i.e. the HTML) synchronously into an
NSData
(a data buffer). Note that you are not loading any certificates (well, technicallyNSURL
will load them internally, but this code is most definitely not putting them into theNSData
) - You are opening an input stream and sticking the data (a bit of HTML, no certificates!) into it.
- You have implemented
NSStream
's delegate methodstream:handleEvent:
and are attempting to read the kCFStreamPropertySSLPeerCertificates property. This property will be empty since the stream contains only a bit of HTML data, nothing else. - You are casting the empty property to an
NSArray
. - The loop is not executed because the array is
NULL
.
Using NSStream
/CFStream
is not necessary for the task at hand. And most definitely you don't have to go through NSURLConnection
first and then through NSStream
.
To retrieve SSL server certificates, stick to a simple, asynchronous NSURLConnection
and use its delegate methods to access the certificates:
// 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
}
精彩评论