Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS - Install SSL certificate programmatically

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.

like image 265
ridan Avatar asked Oct 09 '12 11:10

ridan


People also ask

How do I install SSL certificate on iPhone?

If you want to turn on SSL/TLS trust for that certificate, go to Settings > General > About > Certificate Trust Settings. Under "Enable full trust for root certificates," turn on trust for the certificate. Apple recommends deploying certificates via Apple Configurator or Mobile Device Management (MDM).

How do I fix certificate not trusted iOS 15?

Root certificates on iPhone and iPad This certificate won't be trusted for websites until you enable it in Certificate Trust Settings.” The user can then trust the certificate on the device by going to Settings > General > About > Certificate Trust Settings.


2 Answers

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.

like image 107
Flovdis Avatar answered Oct 01 '22 23:10

Flovdis


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");
    }
like image 39
Yogendra Singh Avatar answered Oct 01 '22 23:10

Yogendra Singh