简体   繁体   中英

SSL pinning not working (Objective-C, using NSURLSession)

NOTE: The same SSL pinning on working on Android counterpart application. So did iOS changed something? Are there many number of certificates on the server for my url and they keep rotating everyday?

Questions are:

  1. SSL Pinning can be achieved by certificate pinning only, then why doesn't it work?

  2. If some one has a clear explanation of how to do it using public key? Please explain.

First I want to explain how did I get local certificate. I think it's pretty straight. I just typed in https://ez-pay.io and then I clicked on the lock icon and downloaded the certificate. If you know what I mean. Now I think this could be the problem too. My question is: Is it the right way to download the certificate?

Ok let's assume this is right. I embedded or copy pasted the certificate into my Xcode project.

Now here is the code to fetch remote (server) certificate and compare it with the local one:

- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler
{
    NSLog(@"SECURITY : didReceiveChallenge");

    // REMOTE CERTIFICATE
    SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;

    // Evaluate server certificate [Whether the certificate is valid or not] --
    SecTrustResultType result;
    SecTrustEvaluate(serverTrust, &result);
    BOOL isRemoteCertValid = (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed);

    // Remote certificate object --
    SecCertificateRef certificateRemote = SecTrustGetCertificateAtIndex(serverTrust, 0);
    // Returns a DER representation of a certificate --
    NSData *remoteCertData = CFBridgingRelease(SecCertificateCopyData(certificateRemote));

    NSData *localCerData = [self GetLocalCertificateData];

    // base 64 encoding of remote certificate --
    NSString* strRemote = [remoteCertData base64EncodedStringWithOptions:0]; // get string from certificate --

    NSString *strLocal = [self  GetLocalCertificateStringForPublicKey];

    // The pinning check -- compare the remote and local certificate data / string --
//    if (isRemoteCertValid && [strLocal isEqualToString:strRemote] )
    if (isRemoteCertValid && [localCerData isEqualToData:remoteCertData] )
    {
        NSLog(@"SECURITY : OK ");
    }
    else
    {
        NSLog(@"SECURITY : FAILS");
        isCertificateValid = false;
    }
}

- (NSData *)GetLocalCertificateData
{
    if ( MODE == PROD_US)
    {
        NSString *pathToCert = [[NSBundle mainBundle]pathForResource:@"prod_ezpay" ofType:@"cer"];
        NSData *localCertificate = [NSData dataWithContentsOfFile:pathToCert];
        return localCertificate;
    }
    else if (MODE == PREP_US)
    {
        NSString *pathToCert = [[NSBundle mainBundle]pathForResource:@"prepEZPAY" ofType:@"cer"];
        NSData *localCertificate = [NSData dataWithContentsOfFile:pathToCert];
        return localCertificate;
    }

    return nil;
}

Now the problem is that comparison of certificates Data always fails:

[localCerData isEqualToData:remoteCertData] // Always false

I have been trying many different approaches checked 5-6 links on google, all have same approach. This project is a bit old, 3-4 years and written in Objective-C.

I tried 3 approaches:

  1. Converting certificates into NSData and compare -- didn't work.

  2. Converting certificate into NSData and then to Base64String -- did not work ..

  3. Also a hack - I printed the data and saved it in string format and hard coded it in the app and then next time onwards keep comparing it with server's certificate data. This approach only works for one day and next day server's certificate data changes. Don't know what is happening.

Please suggest what is wrong in here?

  • I figured out the issue .

    • You must always download ssl certificate when you are out of your local office network or wifi . Because if you download your certificate within vpn / office LAN / office wifi , your certificate will be tempered / overwritten .
    • Thus when you will pin the certificate which you downloaded in your secure private office network then , then it will never match the remote certificate as remote certificate is always public.

      Therefore , download the certificate from open wifi or your own data plan :) and then pin this certificate in your code and i am sure then it will match the remote certificate.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM