public
Last active

iOS SSL based NSURLConnection to a site using a self-signed certificate

  • Download Gist
MyWebFetcher.m
Objective-C
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
#if ! __has_feature(objc_arc)
#error THIS CODE MUST BE COMPILED WITH ARC ENABLED!
#endif
static CFArrayRef certs;
 
@implementation MyWebFetcher
 
+ (void)initialize
{
if(self == [MyWebFetcher class]) {
// I had a crt certificate, needed a der one, so found this site:
// http://fixunix.com/openssl/537621-re-der-crt-file-conversion.html
// and did this from Terminal: openssl x509 -in crt.crt -outform der -out crt.der
NSString *path = [[NSBundle mainBundle] pathForResource:@"crt" ofType:@"der"];
assert(path);
NSData *data = [NSData dataWithContentsOfFile:path];
assert(data);
 
/* Set up the array of certs we will authenticate against and create cred */
SecCertificateRef rootcert = SecCertificateCreateWithData(NULL, CFBridgingRetain(data));
const void *array[1] = { rootcert };
certs = CFArrayCreate(NULL, array, 1, &kCFTypeArrayCallBacks);
CFRelease(rootcert); // for completeness, really does not matter
}
}
 
#pragma mark -
#pragma mark Connection Authentication Handling
 
@implementation MyWebFetcher (NSURLConnectionDelegate)
 
- (BOOL)connection:(NSURLConnection *)conn canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{
#pragma unused(conn)
 
NSString * challenge = [protectionSpace authenticationMethod];
NSLog(@"canAuthenticateAgainstProtectionSpace challenge %@ isServerTrust=%d", challenge, [challenge isEqualToString:NSURLAuthenticationMethodServerTrust]);
if ([challenge isEqualToString:NSURLAuthenticationMethodServerTrust]) {
return YES;
}
 
return NO;
 
}
 
/* Look to see if we can handle the challenge */
- (void)connection:(NSURLConnection *)conn didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
#pragma unused(conn)
NSLog(@"didReceiveAuthenticationChallenge %@ FAILURES=%d", [[challenge protectionSpace] authenticationMethod], (int)[challenge previousFailureCount]);
 
/* Setup */
NSURLProtectionSpace *protectionSpace = [challenge protectionSpace];
assert(protectionSpace);
SecTrustRef trust = [protectionSpace serverTrust];
assert(trust);
CFRetain(trust); // Make sure this thing stays around until we're done with it
NSURLCredential *credential = [NSURLCredential credentialForTrust:trust];
 
#if 0 // moved to initialize for re-use
NSString *path = [[NSBundle mainBundle] pathForResource:@"Lot18-CA" ofType:@"der"];
assert(path);
NSData *data = [NSData dataWithContentsOfFile:path];
assert(data);
 
SecCertificateRef rootcert = SecCertificateCreateWithData(NULL, CFBridgingRetain(data));
const void *array[1] = { rootcert };
/* Set up the array of certs we will authenticate against and create cred */
CFArrayRef certs = CFArrayCreate(NULL, array, 1, &kCFTypeArrayCallBacks);
CFRelease(rootcert); // for completeness, really does not matter
CFRelease(rootcert); // for completeness, really does not matter
#endif
 
/* Build up the trust anchor using our root cert */
 
int err;
SecTrustResultType trustResult = 0;
err = SecTrustSetAnchorCertificates(trust, certs);
if (err == noErr) {
err = SecTrustEvaluate(trust,trustResultP);
}
CFRelease(trust); // OK, now we're done with it
 
// http://developer.apple.com/library/mac/#qa/qa1360/_index.html
BOOL trusted = (err == noErr) && ((trustResult == kSecTrustResultProceed) || (trustResult == kSecTrustResultConfirm) || (trustResult == kSecTrustResultUnspecified));
 
// Return based on whether we decided to trust or not
if (trusted) {
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
} else {
NSLog(@"Trust evaluation failed for service root certificate");
[[challenge sender] cancelAuthenticationChallenge:challenge];
}
}
 
@end
README.txt
1 2 3 4 5
This code was taken from: http://blog.wingsofhermes.org/?p=58&cpage=1, and the following done to it:
 
- code was ARCified
- the "certificate authority certificate", provided to me as a .crt file, was converted to a der format needed by iOS, and is read from the bundle
- the repetitive Security framework code was done once in the initialize method

Hi
I try to test with your code, but I always receive kSecTrustResultRecoverableTrustFailure event. Could you help me ? Thank you.

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.