iPhoneHTTPServer with SSL and certificate

945 Views Asked by At

I'm using the iPhoneHTTPServer sample into my project for using HTTPServer, and host a .plist file with a .ipa to simulate an ad-hoc deployment.

As you may know, since iOS7, the server which hosts files must be secured, and so I'm trying to use a SSL authentication, but it failed.

First, the server seems to start correctly, but it failed when I'm trying to access to my server like this:

NSURL *plistUrl = [NSURL URLWithString:@"itms-services://?action=download-manifest&url=https://localhost:8080/TestMAJ2.plist"];
[[UIApplication sharedApplication] openURL:plistUrl];

I have this error :

NSAssert(NO, @"Security option unavailable - kCFStreamSSLLevel" @" - You must use GCDAsyncSocketSSLProtocolVersionMin & GCDAsyncSocketSSLProtocolVersionMax");

How can I bypass this error? I was trying to removed the kCFStreamSSLLevel of the TLS settings (why not ? ^^), but the connection still don't work, I've got a popup with "Unable to connect to localhost" or something like that ...

About the SSL authentication, the DDKeychain class from the sample was not good because it's Mac's API, so I use this code: How to make iPhoneHTTPServer secure server, and the certificate come from Keychain Access, and it's the certificate that I used for signing my app. Maybe it's not the correct certificate ? Or the correct piece of code ? Do you know a very simple example of using SecureHTTPServer in iOS?

1

There are 1 best solutions below

5
Nicolas Yuste On

I have the SSL certificate working perfectly with a .html file. I am having problems with the .manifest and the .ipa files.

What I did for the SSL is creating MyHTTPConnection class that implements the following:

- (NSArray *)sslIdentityAndCertificates
{
   SecIdentityRef identityRef = NULL;
   SecCertificateRef certificateRef = NULL;
   SecTrustRef trustRef = NULL;
   NSString *thePath = [[NSBundle mainBundle] pathForResource:@"server" ofType:@"pfx"];
   NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath];
   CFDataRef inPKCS12Data = (__bridge CFDataRef)PKCS12Data;
   CFStringRef password = CFSTR("test123");
   const void *keys[] = { kSecImportExportPassphrase };
   const void *values[] = { password };
   CFDictionaryRef optionsDictionary = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);

   OSStatus securityError = errSecSuccess;
   securityError =  SecPKCS12Import(inPKCS12Data, optionsDictionary, &items);
   if (securityError == 0) {
       CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex (items, 0);
       const void *tempIdentity = NULL;
       tempIdentity = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemIdentity);
       identityRef = (SecIdentityRef)tempIdentity;
       const void *tempTrust = NULL;
       tempTrust = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemTrust);
       trustRef = (SecTrustRef)tempTrust;
   } else {
       NSLog(@"Failed with error code %d",(int)securityError);
       return nil;
  }

   SecIdentityCopyCertificate(identityRef, &certificateRef);
   NSArray *result = [[NSArray alloc] initWithObjects:(__bridge id)identityRef, (__bridge id)certificateRef, nil];

   return result;
}

Then in the App Delegate I just setted this custom connection class to the httpServer:

 [httpServer setConnectionClass:[MyHTTPConnection class]];

The last thing that you need to do is to add the server.pfx certificate to the bundle. I created the certificate following this tutorial. I just did until you have the server.crt file. Then I converted it to pfx12 in this website. I did this because p12 certificate was not working, I was having this problem.

Chris, could you edit your entry explaining a little bit how you did the manifest thing. I want to do exactly the same as you but I am having troubles with the URLs that you need to open.