Ответ 1
Техническая поддержка Apple указала мне на следующую техническую заметку:
https://developer.apple.com/library/ios/qa/qa1745/_index.html
Подводя итог, то, что мы хотим сделать, не поддерживается.
Наши клиенты хотят использовать решение MDM (решение для управления мобильными устройствами) (MobileIron) для установки клиентских сертификатов на корпоративные устройства iOS, чтобы ограничить доступ к определенным корпоративным веб-сервисам только корпоративным устройствам.
MobileIron устанавливает сертификат клиента в "Настройки" > "Основные" > "Профили", который является стандартным положением для сертификатов в iOS, и Safari может отвечать этим сертификатом, когда корпоративный веб-сервис ставит перед ним проблемы.
Но мне нужно то же самое, что и в пользовательском приложении. Когда наше приложение получает вызов для сертификата, я должен иметь возможность ответить сертификатом из "Настройки" > "Основные" > "Профили". У меня есть примеры ответов с сертификатом, который поставляется вместе с нашим приложением, и с сертификатом, который наше приложение хранит в своей собственной цепочке ключей, но у меня нет примера ответа с сертификатом, установленным на устройстве, в разделе "Настройки" > "Основные" > "Профили".
Может ли кто-нибудь объяснить мне больше о том, что делает метод протокола NSURLAuthenticationChallengeSender
-performDefaultHandlingForAuthenticationChallenge:
? Работает ли по умолчанию обработка означает, что iOS эффективно реагирует на вызов от имени приложения? Может ли этот ответ включать сертификат клиента, хранящийся в разделе "Настройки" > "Основные" > "Профили"?
Обновление
Если MDM может установить сертификат клиента в цепочку ключей приложения, это будет идеально.
Техническая поддержка Apple указала мне на следующую техническую заметку:
https://developer.apple.com/library/ios/qa/qa1745/_index.html
Подводя итог, то, что мы хотим сделать, не поддерживается.
Я только что вернулся с места на клиенте, который использовал MobileIron, и хотел сделать именно это. Поддержка разработки MobileIron предоставила нам этот фрагмент кода, который импортирует сертификат, предоставляемый приложением AppConnect Wrapper, с помощью технологии MobileIron Core Config.
Это некрасиво, но, как и было предоставлено ими, мне не разрешили его модифицировать. Это работает! Вы вставляете это в свой AppDelegate.h:
- (NSString *)appConnectConfigChangedTo:(NSDictionary *)newConfig;
И это в ваш AppDelegate.m, сразу после знака прагмы выше:
#pragma mark UIApplicationDelegate implementation
- (NSString *)appConnectConfigChangedTo:(NSDictionary *)newConfig{
//NSLog(@"New config: %@", newConfig); //unsecure
NSLog(@"New config retrieved"); //confirm we got a new config
NSString *certStr = [newConfig valueForKey:@"kUserCert"]; //Store certificate as String
NSString *certPassword = [newConfig valueForKey:@"kUserCert_MI_CERT_PW"]; //Store certificate password as string
NSData *cert = [[NSData alloc] initWithBase64EncodedString:certStr options:0]; //only for iOS7+, decodes base64 encoded certificate
CFDataRef pkcs12Data = (__bridge CFDataRef)cert; //Extract identity & certificate objects from
CFStringRef password = (__bridge CFStringRef)certPassword; //the cert data Identity
SecIdentityRef myIdentity = nil; //Initialize variable for identity
SecCertificateRef myCertificate = nil; //Initialize variable for certificate
OSStatus status = extractIdentityAndTrust(pkcs12Data, password, &myIdentity, nil); //Use Apple-provided method for extracting Identity and Trust
if (status != errSecSuccess || myIdentity == nil) { NSLog(@"Failed to extract identity and trust: %ld", status);} //Likely due to corruption
else { SecIdentityCopyCertificate(myIdentity, &myCertificate); } //This method is supposed to store the Certificate, but Fiori doesn't see it here
const void *certs[] = { myCertificate }; //Initialize an array for one certificate
CFArrayRef certsArray = CFArrayCreate(NULL, certs, 1, NULL); //Make the array the way Apple wants it to be
NSURLCredential *credential = [NSURLCredential credentialWithIdentity:myIdentity certificates:(__bridge NSArray*)certsArray persistence:NSURLCredentialPersistencePermanent]; //MobileIron method of Credential storage
NSMutableDictionary *secIdentityParams = [[NSMutableDictionary alloc] init]; //Initialize Dictionary to store identity
[secIdentityParams setObject:(__bridge id)myIdentity forKey:(__bridge id)kSecValueRef]; //Build the secIdentityParams dictionary in the way the next method expects it to be
OSStatus certInstallStatus = SecItemAdd((__bridge CFDictionaryRef) secIdentityParams, NULL); //Add the identity to the keychain for Fiori consumption
if (myIdentity) CFRelease(myIdentity); //Free
if (certsArray) CFRelease(certsArray); //Up
if (myCertificate) CFRelease(myCertificate); //Memory
return nil; //Success
}
// Copied from Apple document on Certificates:
// http://developer.apple.com/library/mac/documentation/security/conceptual/CertKeyTrustProgGuide/CertKeyTrustProgGuide.pdf
OSStatus extractIdentityAndTrust(CFDataRef inP12data, CFStringRef password, SecIdentityRef *identity, SecTrustRef *trust){
OSStatus securityError = errSecSuccess;
const void *keys[] = { kSecImportExportPassphrase };
const void *values[] = { password };
CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
CFArrayRef items = nil;
securityError = SecPKCS12Import(inP12data, options, &items);
if (securityError == errSecSuccess) {
CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex(items, 0);
if (identity && CFDictionaryGetValueIfPresent(myIdentityAndTrust, kSecImportItemIdentity, (const void **)identity)) {
CFRetain(*identity);
}
if (trust && CFDictionaryGetValueIfPresent(myIdentityAndTrust, kSecImportItemTrust, (const void **)trust)) {
CFRetain(*trust);
}
}
if (options) {CFRelease(options);}
if (items) {CFRelease(items);}
return securityError;
}
После того как вы создали свое приложение, попросите администратора MobileIron "обернуть" приложение, чтобы он мог использовать AppConnect. Как только это будет сделано, и развернутое приложение будет развернуто для тестирования пользователей с помощью MobileIron, настройте базовую конфигурацию, которая принимает пользовательский сертификат, специфичный для предоставленного пользователя, и подталкивает его к подготовленным устройствам под ключом Core Config "kUserCert".
MobileIron AppConnect 2.1 обновление решает эту проблему, никакого специального кода не требуется. Сертификаты X.509 могут быть перенесены с помощью конфигурации AppConnect, а инфраструктура AppConnect перехватывает любые