iOS - Install SSL certificate programmatically

14,411

Solution 1

It's no enough to import the certificate into the keychain. The new root certificate has also be trusted by the user or system.

Assuming you still have the SecCertificateRef in the variable certificate, use the following code to raise the trust level:

NSDictionary *newTrustSettings = @{(id)kSecTrustSettingsResult: [NSNumber numberWithInt:kSecTrustSettingsResultTrustRoot]};
status = SecTrustSettingsSetTrustSettings(certificate, kSecTrustSettingsDomainUser, (__bridge CFTypeRef)(newTrustSettings));
if (status != errSecSuccess) {
    NSLog(@"Could not change the trust setting for a certificate. Error: %d", status);
    exit(0);
}

Changing the trust level will ask the user in a popup window if he accepts the change.

Solution 2

Swift 4.0

let rootCertPath = Bundle.main.path(forResource: "XXXXX", ofType: "der")
    let rootCertData = NSData(contentsOfFile: rootCertPath!)
    var err: OSStatus = noErr
    let rootCert = SecCertificateCreateWithData(kCFAllocatorDefault, rootCertData!)

    //var result: CFTypeRef1
    let dict = NSDictionary.init(objects: [kSecClassCertificate, rootCert!], forKeys: [kSecClass as! NSCopying, kSecValueRef as! NSCopying])

    err = SecItemAdd(dict, nil)

    if(err == noErr) {
        NSLog("Install root certificate success");
    } else if( err == errSecDuplicateItem ) {
        NSLog("duplicate root certificate entry");
    } else {
        NSLog("install root certificate failure");
    }
Share:
14,411

Related videos on Youtube

ridan
Author by

ridan

Updated on June 10, 2022

Comments

  • ridan
    ridan about 2 years

    I'm writing a phonegap plugin that installs both CA root certificate and user certificate in the app keychain.

    Here is the code used to install the certificate:

    NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:certpath];
    CFDataRef inPKCS12Data = (CFDataRef)PKCS12Data;
    CFStringRef password = (CFStringRef)certPassword;
    const void *keys[] = { kSecImportExportPassphrase };
    const void *values[] = { password };
    CFDictionaryRef optionsDictionary = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
    CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
    OSStatus securityError = SecPKCS12Import(inPKCS12Data, optionsDictionary, &items);
    if (securityError == 0) {
        NSLog(@" *** Certificate install Success ***");
    } else {
        NSLog(@" *** Certificate install Failure ***");
    }
    

    The code above works fine (securityError equals 0). However, I'm obtaining those errors:

    unknown apsd[59] <Warning>: <APSCourier: 0xee1ba80>: Stream error occurred for <APSTCPStream: 0x126940>: TLS Error Code=-9844 "peer dropped connection before responding"
    unknown securityd[638] <Error>: CFReadStream domain: 12 error: 8
    

    That indicates that the device does not accept the installed certificate, so i'm wondering that the certificate is not validated against the CA Root certificate installed on the device.

    Do I have to install the CA Root certificate for the app ?

    Any ideas ?

    P.S: I'm new to Objective-C and XCode environment.

    EDIT:

    The code below is used to store CA root certificat in keychain:

    NSString *rootCertPath = [[NSBundle mainBundle] pathForResource:@"rootca" ofType:@"cer"];
    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");
    }
    

    EDIT:

    It seems that the certificate is not sent to server. I think that I have to send manually the certificate each time an https request is made... I'm looking for a way to catch every https call in phonegap.

    • Frank
      Frank over 11 years
      Have a look [here][1], it's an older SO answer on the same topic. [1]: stackoverflow.com/questions/5323686/…
    • ridan
      ridan over 11 years
      I've tried the same snippet with my cer file, it does not work...
    • Bruno
      Bruno over 11 years
      Generally speaking, there are security questions to be asked if an app can modify the list of trusted CA certificates used globally by the device, especially without explicit user intervention.
    • Frank
      Frank over 11 years
      Bruno:It will add the certificate to the keychain sandbox of your application i.e. no other application will trust your cert.
    • Bruno
      Bruno over 11 years
      @Frank, ah fair enough, sorry, I'm not too familiar with iOS development.
    • Frank
      Frank over 11 years
      Trie to install the full chain of certificates from CA to server, just a guess but the best i can do with the info i have.
    • ridan
      ridan over 11 years
      The root certificate seems to be installed using SecItemAdd method. Now I'm trying to install the user certificate using the same method and by passing the certificate password.
    • iPatel
      iPatel over 10 years
  • Admin
    Admin almost 9 years
    undeclared identifier kSecTrustSettingsResult and I already imported the Security class?! What am I doing wrong?
  • Kevin Owens
    Kevin Owens about 8 years
    This appears to rely on the open source security library provided by Apple, and specifically the defines given in SecTrustSettings.h. More in the above answer than meets the eye!
  • Nicolas Miari
    Nicolas Miari almost 8 years
    Any hope I can achieve the same trust setting without importing this huge (and old) library, written mostly in C++? At least a pointer to the underlying Security.framework functions (likely) wrapped underneath?
  • Austin
    Austin about 7 years
    How do you even add the libsecurity_keychain library to your project? I can't get it to build. Anyone able to get this to work?