views:

1222

answers:

5

I'm fighting with a client certificate authentication. When a server needs a credential (a certificate in this case), this method is invoked from NSURLConnection delegate:

  • (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge

I want to load a certificate from a file, fill a credential and run this method:

[[challenge sender] useCredential:[self credential] forAuthenticationChallenge:challenge];

But I don't know how to initialize (or fill) a SecIdentityRef parameter. Here is my code that creates the credentials:

NSString *certPath = [[NSBundle mainBundle] pathForResource:@"certificate" ofType:@"cer"];
NSData *certData = [[NSData alloc] initWithContentsOfFile:certPath];

SecIdentityRef myIdentity;  // ???

SecCertificateRef myCert = SecCertificateCreateWithData(NULL, (CFDataRef)certData);
[certData release];
SecCertificateRef certArray[1] = { myCert };
CFArrayRef myCerts = CFArrayCreate(NULL, (void *)certArray, 1, NULL);
CFRelease(myCert);
NSURLCredential *credential = [NSURLCredential credentialWithIdentity:myIdentity
                                  certificates:(NSArray *)myCerts
                                   persistence:NSURLCredentialPersistencePermanent];
CFRelease(myCerts);

Does anybody know how to solve it? Thanks.

+1  A: 

I've finally found the solution, but a new problem is here:

my client doesn't send the certificate to the server. After the server asks for the certificate, the application runs this method:

  • (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge

and I fill the credential (like I mentioned above), but the connection ends with an error: "NSURLErrorDomain -1206". According to the server logs the client certificate is not sent by the application.

Has anybody any experience with this behaviour? Do I need to somehow verify the cerficate in the application? Or anything else to make it work? I can provide my current code if it helps. Thanks for any ideas...

Kamil
A: 

Of course the problem was with the iPhone simulator in xcode :) After updating to version 3.1 it started to work...

Kamil
A: 

Can you specify how you ended up initialising the SecIdentityRef in your example?

Chris Miles
+1  A: 

I use these steps:

  1. extract SecIdentityRef from the pkcs12 certificate file using SecPKCS12Import function
  2. use SecIdentityCopyCertificate function to get SecCertificateRef

and the rest (a credential initialization) is the same as in my question... I can put here more code if you want. Note that there is a bug (http://openradar.appspot.com/7090030) in the iphone simulator, so it is not possible to work with a lot of certifcates in the simulator.

Kamil
A: 

I do something like:-

NSURLProtectionSpace *vxProtectionSpace1 = [[NSURLProtectionSpace alloc] initWithHost:@"myhost.com" port:443 protocol:@"https" realm:nil authenticationMethod:NSURLAuthenticationMethodClientCertificate];

[[NSURLCredentialStorage sharedCredentialStorage] setCredential:credential forProtectionSpace:myProtectionSpace];

After having created the credentials from a PKCS12 password protected file. It doesnt work in the case of sendSynchronousCall, however for async call it works fine.

Another thing I am getting 2 challenges actually NSURLAuthenticationMethodServerTrust and NSURLAuthenticationMethodClientCertificate.

The 1st is probably because the server side certificate is self-signed, however I have added the same into the keychain as Trusted Root Certificate.

Can anyone point out what I might be missing here?

mayank
you should add a new question describing your full issue, it will draw attention to it and increase chances of getting an actual right answer.
leolobato