Подтвердить что ты не робот

IOS - программно установить сертификат SSL

Я пишу плагин phonegap, который устанавливает как корневой сертификат CA, так и сертификат пользователя в цепочке ключей приложения.

Вот код, используемый для установки сертификата:

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 ***");
}

Код выше работает отлично (securityError равно 0). Однако я получаю эти ошибки:

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

Это означает, что устройство не принимает установленный сертификат, поэтому мне интересно, что сертификат не проверен на сертификат CA Root, установленный на устройстве.

Нужно ли устанавливать сертификат CA Root для приложения?

Любые идеи?

P.S: Я новичок в среде Objective-C и XCode.

EDIT:

Код ниже используется для хранения корневого сертификата CA в цепочке ключей:

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");
}

ИЗМЕНИТЬ

Кажется, что сертификат не отправляется на сервер. Я думаю, что я должен отправлять сертификат вручную каждый раз, когда выполняется запрос https... Я ищу способ поймать каждый вызов https в телефонном разговоре.

4b9b3361

Ответ 1

Недостаточно импортировать сертификат в цепочку ключей. Новый корневой сертификат также может доверять пользователю или системе.

Предполагая, что у вас все еще есть SecCertificateRef в переменной certificate, используйте следующий код для повышения уровня доверия:

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);
}

Изменение уровня доверия спросит пользователя во всплывающем окне, если он примет изменение.

Ответ 2

Что я искал, установив "Всегда доверять" для сертификата System keychain,

// Trust always, as root certificated.
    NSDictionary *newTrustSettings = @{(id)kSecTrustSettingsResult: [NSNumber numberWithInt:kSecTrustSettingsResultTrustRoot]};
    status = SecTrustSettingsSetTrustSettings(myCertificate, kSecTrustSettingsDomainAdmin, (__bridge CFTypeRef)(newTrustSettings));