iOS客户端证书和移动设备pipe理
我们的客户希望使用MDM(移动设备pipe理)解决scheme(MobileIron)将客户端证书安装到企业iOS设备上,以便仅限企业设备访问某些企业Web服务。
MobileIron将客户端证书安装到设置>常规>configuration文件 (这是iOS中的证书的默认位置),并且当企业Web服务挑战一个证书时,Safari可以使用此证书进行响应。
但是我需要从一个自定义应用程序中发生相同的事情。 当我们的应用程序获得证书的挑战时,我需要能够通过设置>常规>configuration文件中的证书进行响应。 我有一个与我们的应用程序捆绑在一起的证书,以及我们的应用程序存储在其自己的钥匙串中的证书进行响应的示例,但是我没有在设置>常规>configuration文件中使用设备上安装的证书进行响应的示例。
任何人都可以向我解释更多关于什么NSURLAuthenticationChallengeSender
协议方法-performDefaultHandlingForAuthenticationChallenge:
做什么? 默认处理是否意味着iOS有效地代表应用程序回应挑战? 此响应是否可以包含存储在设置>常规>configuration文件中的客户端证书?
更新
如果MDM可以将客户端证书安装到应用程序钥匙链中,那将是完美的。
苹果技术支持人员向我指出了以下技术说明:
https://developer.apple.com/library/ios/qa/qa1745/_index.html
总而言之,我们想要做的是不被支持的。
我刚刚从一位使用MobileIron的客户那里回来,他正在考虑这样做。 MobileIron开发支持为我们提供了这段代码,它通过MobileIron的Core Config技术导入由AppConnect包装器提供的证书。
这不是很好,但是由于它们提供了我不允许修改它。 它虽然工作! 你插入到你的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's 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; }
构build应用程序后,要求MobileIronpipe理员“包装”应用程序,以便使用AppConnect。 一旦完成并且将包装的应用程序部署到通过MobileIrontesting用户,请设置一个核心configuration,为configuration的用户提供特定的用户证书,并将其推送到核心configuration密钥“kUserCert”下的configuration设备。
MobileIron的AppConnect 2.1更新解决了这个问题,不需要特殊的代码。 可以使用AppConnectconfiguration来推送X.509证书,并且AppConnect框架可以在使用符合条件的证书进行响应时拦截任何身份validation挑战 。 Certs可以在首次启动时立即创build,稍后撤销,按用户定制或按设备定制,不同的URL可以使用不同的证书。
如果有人正在使用此页面上的代码段,请停止,这不是必需的。 在封装未修改的应用程序或链接AppConnect框架之后,将MI_AC_CLIENT_CERT_1密钥添加到AppConnectconfiguration中,指向证书注册configuration(即SCEP,Entrust,Symantec PKI,PIV-D等)。 添加一个带有URL的MI_AC_CLIENT_1_RULE键(带有可选的通配符)。 没有步骤3.您的应用程序现在将自动使用证书进行身份validation。
完整的详细信息在MobileIron的AppConnect和AppTunnel指南文档中的“从AppConnect应用程序到企业服务的证书authentication”下。