4

How do I add my own Root Certificate Authority (CA) file to a device's Root CA list in Swift?

I am trying to convert the Objective-C code below into Swift, but I do not know how to write the dictionary correctly for this scenario.

Swift:

let rootCertPath = NSBundle.mainBundle().pathForResource("server", ofType: "crt")!
let rootCertData = NSData(contentsOfFile: rootCertPath)
let rootCert     = SecCertificateCreateWithData(kCFAllocatorDefault, rootCertData)

// Error: '_' is not convertible to 'CFStringRef'
let dict =
[
    kSecClass:    kSecClassCertificate,
    kSecValueRef: rootCert
] as CFDictionaryRef

error = SecItemAdd(dict, result)

Objective-C:

NSString *rootCertPath = [[NSBundle mainBundle] pathForResource:@"server" ofType:@"crt"];
NSData *rootCertData = [NSData dataWithContentsOfFile:rootCertPath];

OSStatus err = noErr;
SecCertificateRef rootCert = SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef) rootCertData);

CFTypeRef result;

NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
(id)kSecClassCertificate, kSecClass,
rootCert, kSecValueRef,
nil];

err = SecItemAdd((CFDictionaryRef)dict, &result);

if( err == noErr) {
    NSLog(@"Install root certificate success");
} else if( err == errSecDuplicateItem ) {
    NSLog(@"duplicate root certificate entry");
} else {
    NSLog(@"install root certificate failure");
}

Source: iOS - Install SSL certificate programmatically

Community
  • 1
  • 1
Christopher Markieta
  • 5,674
  • 10
  • 43
  • 60

1 Answers1

1

I have found a solution that seems to work but I'm not entirely sure if it is the correct method. Please correct me if I am wrong.

First I needed to convert the certificate from *.crt to *.der because it kept creating a nil SecCertificate.

openssl x509 -in server.crt -out server.der -outform DER

My code:

func installRootCertificate() -> Bool
{
    var result: UnsafeMutablePointer<Unmanaged<AnyObject>?> = nil
    var error = noErr

    let rootCertPath = NSBundle.mainBundle().pathForResource("server", ofType: "der")!
    let rootCertData = NSData(contentsOfFile: rootCertPath)!
    let rootCert     = SecCertificateCreateWithData(kCFAllocatorDefault, rootCertData)

    let kSecClassValue            = NSString(format: kSecClass)
    let kSecClassCertificateValue = NSString(format: kSecClassCertificate)
    let kSecValueRefValue         = NSString(format: kSecValueRef)

    let dict =
    [
        kSecClassValue:    kSecClassCertificateValue,
        kSecValueRefValue: rootCert.takeRetainedValue()
    ] as CFDictionaryRef

    error = SecItemAdd(dict, result)

    if(error == noErr)
    {
        println("Installed root certificate successfully");

        return true
    }
    else if(error == errSecDuplicateItem)
    {
        println("Duplicate root certificate entry");
    }
    else
    {
        println("Install root certificate failure")
    }

    return false
}
Christopher Markieta
  • 5,674
  • 10
  • 43
  • 60
  • @gaussblurinc: Not really. If you're planning to deploy to the App Store, you'll need to purchase an authorized cert that Apple approves. You can find a bunch that Apple supports for pretty cheap. https://support.apple.com/en-ca/HT204132 – Christopher Markieta Oct 05 '15 at 16:47
  • Am I right that you said about apple restrictions to ssl certificates? so, if I want to use ssl certificates in my server interaction workflow, I need to use authorized trusted certificates that are appeared in list that you provide? – gaussblurinc Oct 06 '15 at 05:47
  • @gaussblurinc Yes. You will not be able to use self-signed certificates without disabling some security features that will prevent you from getting app approval from Apple. However, you can have your users manually install your self-signed trusted CA without disabling these security features. To do this, you will have the root CA be opened with Safari or Mail via this method: https://www.bomgar.com/docs/content/platforms/apple-ios/installiosconfigurationprofiles.htm But this is not recommended for a deployed app. I would not trust your root CA personally. It's much simpler to buy a cert for $5 – Christopher Markieta Oct 06 '15 at 17:39
  • @ChristopherMarkieta this above code working in alamofire webservice? – Iyyappan Ravi Jan 21 '17 at 13:26
  • @IyyappanRavi I have no clue. If you're planning to release an app on the App Store, you should really just buy a cert rather than use a self-signed one. – Christopher Markieta Jan 21 '17 at 19:20
  • Does Apple allow using my custom CA with certificate pinning? – beppe9000 Mar 27 '17 at 19:13
  • @beppe9000 I'm not sure about that. You can manually install your custom CA via Safari or Mail, but instructing your users to do this is suspicious. Having your custom CA being listed in Apple's list of trusted CAs would cost a lot of money. If you want to put your app on the App Store just buy a cert. – Christopher Markieta Mar 27 '17 at 20:20
  • I meant verifying at application level, without using the system CA list. Something like supplying the network socket with its own CA list. – beppe9000 Mar 28 '17 at 21:08