•   almost 12 years ago

iOS access denied error

Did anyone succeed with iOS ?
I have installed the certificate on my iPhone, when i try with the demo store it work perfectly but in my application its doesn't work. I always receive this response: Server Error


403 - Forbidden: Access is denied.
You do not have permission to view this directory or page using the credentials that you supplied.

I use NSURLRequest to make the HTTPRequest.
Did anyone have a sample code ?
Thanks,

  • 18 comments

  •   •   almost 12 years ago

    Have you installed the certificate in your app's Keychain? Your app can't use the certificate from the main Keychain.

    Once you get it installed, your code has to handle passing the certificate to the server.

    If I ever get the code to actually work, I'll throw it on Github.

  •   •   almost 12 years ago

    How can i handle passing the certificate to the server?

  •   •   almost 12 years ago

    implement

    - (void)connection:(NSURLConnection *)conn didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge

    in your NSURLConnection delegate.

    Eventually send the message

    [challenge.sender useCredential:theCredential forAuthenticationChallenge:challenge];

    theCredential is a NSURLCredential.

    I'll post a sample in a couple of days, once my code isn't so crappy.

  •   •   almost 12 years ago

    I am also having some trouble with this. Ive been scouring the internet for a few days trying to find the solution :S.
    I'm also using ASIHTTPRequest instead of just the NS stuff too. I wonder if ASI can't handle this kind of request or something.

    Or more so it's not that im getting the 403 error, I'm actually getting an SSL error possibly due to the fact that the Cert is self signed. I'm not 100% sure. I pass the request the Identity I grab out of the p12 file, but that doesn't seem to work.

    Error Domain=ASIHTTPRequestErrorDomain Code=1 "A connection failure occurred: SSL problem (Possible causes may include a bad/expired/self-signed certificate, clock set to wrong date)"

  •   •   almost 12 years ago

    Hey, I have been trying to fetch the basic information of my remote chip through the iPhone Simulator, but I keep getting a 403 error.

    I have implemented '- (void)connection:(NSURLConnection *)conn didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge', and I am sending a SecIdentityRef containing a certificate that is included in my application bundle. However, I am never getting any response other than 403.

    If I install a certificate on my iPhone, I can access https://remote.mintchipchallenge.com/ through safari. Has anybody figured out how to do it from within an app?

  •   •   almost 12 years ago

    I assume you're doing this in your method:

    [challenge.sender useCredential:someCredential forAuthenticationChallenge:challenge];

    You need to respond to two types of challenges ([[challenge protectionSpace] authenticationMethod]) in your method:

    1) NSURLAuthenticationMethodServerTrust - this is the challenge for the host server's self-signed certificate. Use

    [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]

    2) NSURLAuthenticationMethodClientCertificate - this is the challenge asking for your certificate. Use the credential from your identity here.

  •   •   almost 12 years ago

    The code I use (with all formatting missing):

    - (void)connection:(NSURLConnection *)conn didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
    {
    if (NSURLAuthenticationMethodServerTrust == [[challenge protectionSpace] authenticationMethod]) {
    [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
    } else if (NSURLAuthenticationMethodClientCertificate == [[challenge protectionSpace] authenticationMethod]) {
    [challenge.sender useCredential:identityCredential forAuthenticationChallenge:challenge];
    }
    }

  •   •   almost 12 years ago

    how do you initialize identityCredential ?

    Thanks,

  •   •   almost 12 years ago

    Get the certificate from your SecIdentityRef with

    SecCertificateRef certificateRef;
    SecIdentityCopyCertificate(secIdentityRef, &certificateRef);

    Stick the certificate in an array, then use

    [NSURLCredential credentialWithIdentity:secIdentityRef certificates:arrayWithCertificateInIt persistence:NSURLCredentialPersistenceForSession];

  •   •   almost 12 years ago

    This is my code in didReceiveAuthenticationChallenge method:
    SecIdentityRef identity = NULL;

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

    SecCertificateRef myCert = SecCertificateCreateWithData(NULL, (CFDataRef)certData);
    SecCertificateRef certArray[1] = { myCert };
    CFArrayRef myCerts = CFArrayCreate(NULL, (void *)certArray, 1, NULL);

    SecIdentityCopyCertificate(identity, &myCert);

    NSURLCredential *cred = [[NSURLCredential alloc] initWithIdentity:identity certificates:(NSArray*)myCerts persistence:NSURLCredentialPersistencePermanent];

    [challenge.sender useCredential:cred forAuthenticationChallenge:challenge];

    myCert is always null but my certData is not null.
    When i pass myCert in SecIdentityCopyCertificate i have an BAD ACCESS ERROR.
    Do you have any idea why myCert is null?

    Thanks,

  •   •   almost 12 years ago

    Thanks for the help, but I am still getting a 403 error. Here is what I have so far (comments removed):

    - (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodServerTrust) {
    [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
    } else if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodClientCertificate) {
    SecIdentityRef identity = [self getClientCertificate];

    SecCertificateRef certificateRef;
    SecIdentityCopyCertificate(identity, &certificateRef);
    CFArrayRef certificateArray = CFArrayCreate(NULL, (const void **)certificateRef, 1, NULL);

    NSURLCredential *identityCredential = [NSURLCredential credentialWithIdentity:identity certificates:(__bridge NSArray *)certificateArray persistence:NSURLCredentialPersistenceForSession];
    [challenge.sender useCredential:identityCredential forAuthenticationChallenge:challenge];
    }
    }

    And my getClientCertificate looks like this:

    - (SecIdentityRef)getClientCertificate {
    SecIdentityRef identityApp = nil;
    NSString *thePath = [[NSBundle mainBundle] pathForResource:@"Certificate ID" ofType:@"p12"];
    NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath];
    CFDataRef inPKCS12Data = (__bridge CFDataRef)PKCS12Data;
    CFStringRef password = CFSTR("Certificate Password");
    const void *keys[] = { kSecImportExportPassphrase };
    const void *values[] = { password };
    CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
    CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
    OSStatus securityError = SecPKCS12Import(inPKCS12Data, options, &items);
    CFRelease(options);
    CFRelease(password);
    if (securityError == errSecSuccess) {
    NSLog(@"Success opening p12 certificate. Items: %ld", CFArrayGetCount(items));
    CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);
    identityApp = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity);
    } else {
    NSLog(@"Error opening Certificate.");
    }
    return identityApp;
    }

    I am getting every success message, yet I still get a 403 error. When I run my app the NSURLAuthenticationMethodServerTrust is sent, but I never receive the NSURLAuthenticationMethodClientCertificate. Any idea why?

  •   •   almost 12 years ago

    OK, I finally solved this... Here is what the two most important methods look like:

    - (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
    return true;
    }

    - (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    NSLog(@"Challenge Accepted");
    if ([challenge previousFailureCount] == 0) {
    if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodServerTrust) {
    NSLog(@"Challenge Trust");
    [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
    } else if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodClientCertificate) {
    NSLog(@"Challenge Certificate");
    SecIdentityRef identity = [self getClientCertificate];

    NSURLCredential *identityCredential = [NSURLCredential credentialWithIdentity:identity certificates:nil persistence:NSURLCredentialPersistenceForSession];
    [challenge.sender useCredential:identityCredential forAuthenticationChallenge:challenge];
    }
    } else {
    NSLog(@"Cancel Challenges");
    [challenge.sender cancelAuthenticationChallenge:challenge];
    }
    }

    I am success fully connecting and pulling the xml from their servers :)

    Next Question... I am currently putting it in the application bundle and loading it from there. Any ideas on how to get the certificate from the "profiles" on the iPhone?

  •   •   almost 12 years ago

    Thanks, it works for me too !

  •   •   almost 12 years ago

    I also got it working like the above method, but I'd like to point something out that I found out later.

    From the NSURLConnection.h file:
    @protocol NSURLConnectionDelegate
    @optional
    - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
    - (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection;
    - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;

    // Deprecated authentication delegates.
    - (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace;
    - (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
    - (void)connection:(NSURLConnection *)connection didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
    @end

    As you can see, the canAuthenticateAgainstProtectionSpace, and didReceiveAuthenticationChallenge are Deprecated.
    All you need is to use willSendRequestForAuthenticationChallenge.

    Here is what my method looks like.
    - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    [challenge.sender useCredential:self.api.certificateHandler.credential forAuthenticationChallenge:challenge];
    }

    Happy Mintchipping!
    As for getting the pkcs12 file into the app without explicitly embedding it... that one is a little tricky ;)

  •   •   almost 12 years ago

    Has anyone looked at creating a Value Request packet? This ASN.1 stuff is sapping my will to live.

  •   •   almost 12 years ago

    Does anyone else have this problem? I'm getting OSStatus of -26275 (errSecDecode) when I call SecPKCS12Import().

    According to the documentation, errSecDecode means either the blob can't be read or it is malformed. This occurred on both my certificates. Can anyone shed some light on this one? Thanks!

  •   •   almost 12 years ago

    I've done some more research, and i found 'Junos Pulse' which is an iOS app that can read certificates from Settings->General->Profiles, and use them without a password similarly to Safari and Mail. I don't know how they do it though any ideas?

  •   •   almost 12 years ago

    With regards to my problem of getting errSecDecode from calling SecPKCS12Import while running on the simulator, I've solved this by upgrading to iOS 5.1 sdk with XCode 4.3.2. Cheers

Comments are closed.