Create SSL connection using certificate

邮差的信 提交于 2019-11-28 06:39:15

If this is a self signed certificate to be used in server trust authentication, you should do the following:

  1. Convert the .CRT encoded certificate into a .DER encoded certificate. On the terminal type:

    $: openssl x509 -in certificate.crt -outform der -out "com.server.trust_cert.der"

    (choose your own meaningful name)

    Put the .DER encoded certificate into the bundle.

  2. Implement the method connection:didReceiveAuthenticationChallenge: as follows. Important: always check for errors and bail out and let the authentication fail if anything is wrong!!

    Test it thoroughly!

- (void)connection:(NSURLConnection *)connection
    didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    if ([[[challenge protectionSpace] authenticationMethod] isEqualToString: NSURLAuthenticationMethodServerTrust])
    {
        do
        {
            SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust];
            if (serverTrust == nil)
                break; // failed

            SecTrustResultType trustResult;
            OSStatus status = SecTrustEvaluate(serverTrust, &trustResult);
            if (!(errSecSuccess == status))
                break; // fatal error in trust evaluation -> failed

            if (!((trustResult == kSecTrustResultProceed) 
               || (trustResult == kSecTrustResultUnspecified)))
            {
                break; // see "Certificate, Key, and Trust Services Reference" 
                       // for explanation of result codes.
            }

            SecCertificateRef serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0);
            if (serverCertificate == nil)
                break; // failed

            CFDataRef serverCertificateData = SecCertificateCopyData(serverCertificate);
            if (serverCertificateData == nil)
                break; // failed

            const UInt8* const data = CFDataGetBytePtr(serverCertificateData);
            const CFIndex size = CFDataGetLength(serverCertificateData);
            NSData* server_cert = [NSData dataWithBytes:data length:(NSUInteger)size];
            CFRelease(serverCertificateData);

            NSString* file = [[NSBundle mainBundle] pathForResource:@"com.server.trust_cert"
                                                             ofType:@"der"];
            NSData* my_cert = [NSData dataWithContentsOfFile:file];

            if (server_cert == nil || my_cert == nil)
                break; // failed

            const BOOL equal = [server_cert isEqualToData:my_cert];
            if (!equal)
                break; // failed 

            // Athentication succeeded:
            return [[challenge sender] useCredential:[NSURLCredential credentialForTrust:serverTrust]
                          forAuthenticationChallenge:challenge];
        } while (0);

        // Authentication failed: 
        return [[challenge sender] cancelAuthenticationChallenge:challenge];
    }
}

Note:

A possible improvement of the above technique is to use "public key pinning".

Must Reads:

HTTPS Server Trust Evaluation (Official Apple Documentation, Technical Note TN2232)

Certificate, Key, and Trust Services Reference (Official Apple Reference Documentation)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!