Search code examples
iosobjective-cx509

Loading a X509 pem certificate with password. Objective C


i'm a totally newbie in objective-c and iOS programming.

I need to use a REST API, in which the request requires a mutual SSL authentication with a x509 PEM certificate file and a password for the certificate.

My problem is that i don't really know how to do it in objective C, in C# it would be as easy as:

X509Certificate2 myCertificate = new x509Certificate2(certificatePath, certificatePassword);
myRequest.ClientCertificate.Add(myCertificate);

Where "myRequest" just represents the variable of the http request.

I've been looking for a while in many forums and posts, including some old stackoverflow questions. The main tip people give is "use OpenSSL", but i've read in few places (i think even in a stackoverflow question) that Apple has deprecated OpenSSL.

Question: How could i load a .pem x509 certificate with its password to send in a POST request to a external REST API Service, in objective-C language?

Thank you.


Solution

  • My Own Solution:

    Using OpenSSL command to convert .pem file intro pkcs12 certificate:

    openssl pkcs12 -export -in "certificateFile" -inkey "KeyFile" -out "certificate.p12"
    

    Then setting up some code found in this tutorial: https://vanjakom.wordpress.com/tag/nsurlconnection/

    Basically:

    - (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
    {
        NSLog(@"Authentication challenge");
    
        // load cert
        NSString *path = [[NSBundle mainBundle] pathForResource:@"userA" ofType:@"p12"];
        NSData *p12data = [NSData dataWithContentsOfFile:path];
        CFDataRef inP12data = (__bridge CFDataRef)p12data;
    
        SecIdentityRef myIdentity;
        SecTrustRef myTrust;
        OSStatus status = extractIdentityAndTrust(inP12data, &myIdentity, &myTrust);
    
        SecCertificateRef myCertificate;
        SecIdentityCopyCertificate(myIdentity, &myCertificate);
        const void *certs[] = { myCertificate };
        CFArrayRef certsArray = CFArrayCreate(NULL, certs, 1, NULL);
    
        NSURLCredential *credential = [NSURLCredential credentialWithIdentity:myIdentity certificates:(__bridge NSArray*)certsArray persistence:NSURLCredentialPersistencePermanent];
    
        [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
    }
    

    And

    OSStatus extractIdentityAndTrust(CFDataRef inP12data, SecIdentityRef *identity, SecTrustRef *trust)
    {
        OSStatus securityError = errSecSuccess;
    
        CFStringRef password = CFSTR("userA");
        const void *keys[] = { kSecImportExportPassphrase };
        const void *values[] = { password };
    
        CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
    
        CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
        securityError = SecPKCS12Import(inP12data, options, &items);
    
        if (securityError == 0) {
            CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex(items, 0);
            const void *tempIdentity = NULL;
            tempIdentity = CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemIdentity);
            *identity = (SecIdentityRef)tempIdentity;
            const void *tempTrust = NULL;
            tempTrust = CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemTrust);
            *trust = (SecTrustRef)tempTrust;
        }
    
        if (options) {
            CFRelease(options);
        }
    
        return securityError;
    }
    

    "Code copied from the tutorial, did not copy my own modification for my own needs".

    And it's solved