Search code examples
objective-cxmlopenssldigital-signaturexml-signature

How to generate ds:X509Certificate value from .p12 in Objective-C?


I've a private key file .p12.
I'm using Objective-C.

I need to generate Signed digital signature XML like this:

enter image description here

The problem is, I cannot find out how to generate the value in <ds:X509Certificate>. I know it is a public key base64 encoded. But, I can't get the same string after testing various encoding methods..

Need your help!


Solution

  • Found the solution myself. It is so easy.

    Using Apple's security.framework:

    NSString* pfile = [[NSBundle mainBundle] pathForResource:@"rsa_user" ofType:@"p12" ];
    
    // Load Certificate
    NSData *p12data = [NSData dataWithContentsOfFile:pfile];
    CFDataRef inP12data = (__bridge CFDataRef)p12data;
    
    SecIdentityRef myIdentity;
    SecTrustRef myTrust;
    extractIdentityAndTrust(inP12data, &myIdentity, &myTrust);
    
    SecCertificateRef myCertificate;
    SecIdentityCopyCertificate(myIdentity, &myCertificate);
    NSData *certificateData = (__bridge NSData *) SecCertificateCopyData(myCertificate);
    
    // Output certificate base64 value. (This value goes to <ds:X509Certificate> tag )
    NSLog(@"%@", [certificateData base64EncodedString]);
    
    // Helper function
    
    OSStatus extractIdentityAndTrust(CFDataRef inP12data, SecIdentityRef *identity, SecTrustRef *trust)
    {
        OSStatus securityError = errSecSuccess;
    
        CFStringRef password = CFSTR("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);
        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;
    }