iOS客户端证书和移动设备管理

时间:2014-09-19 01:16:57

标签: ios ssl client-certificates mobileiron

我们的客户希望使用MDM(移动设备管理)解决方案(MobileIron)将客户端证书安装到企业iOS设备上,以便仅限访问企业设备的某些企业Web服务。

MobileIron将客户端证书安装到设置>一般>配置文件,这是iOS中证书的默认位置,当公司Web服务对其进行质询时,Safari可以使用此证书进行响应。

但我需要在自定义应用中发生同样的事情。当我们的应用程序受到证书挑战时,我需要能够使用设置>中的证书进行回复。一般>配置文件的。我有一个使用我们的应用程序捆绑的证书进行响应的示例,以及我们的应用程序存储在自己的钥匙串中的证书,但我有一个响应安装在证书上的证书的示例设置>中的设备一般>配置文件

有人可以向我解释一下NSURLAuthenticationChallengeSender协议方法-performDefaultHandlingForAuthenticationChallenge:的作用吗? 默认处理是否意味着iOS有效地代表应用程序响应挑战?此响应是否可以包含存储在设置>中的客户端证书。一般>配置文件

更新

如果MDM可以将客户端证书安装到应用程序钥匙串中,那将是完美的。

3 个答案:

答案 0 :(得分:7)

Apple技术支持向我指出以下技术说明作为回应:

https://developer.apple.com/library/ios/qa/qa1745/_index.html

总结一下,我们不想支持。

答案 1 :(得分:2)

MobileIron的AppConnect 2.1更新解决了这个问题,无需特殊代码。可以使用AppConnect配置推送X.509证书,并且当AppConnect框架可以使用符合条件的证书进行响应时,它会拦截任何authentication challenges。 Certs可以在首次启动时动态创建,稍后撤销,按用户或按设备自定义,不同的URL可以使用不同的证书。

如果有人在此页面上使用代码段,请停止,不需要。在包装未修改的应用程序或链接到AppConnect框架后,将MI_AC_CLIENT_CERT_1密钥添加到AppConnect配置,指向证书注册配置(即SCEP,Entrust,Symantec PKI,PIV-D等)。添加带有URL的MI_AC_CLIENT_1_RULE键(带有可选的通配符)。没有第3步。您的应用程序现在将自动使用证书进行身份验证。

完整详细信息位于 MobileIron的AppConnect和AppTunnel指南文档中,位于“从AppConnect应用程序到企业服务的证书身份验证”下。

答案 2 :(得分:1)

我刚刚从一位正在使用MobileIron的客户现场回来,并且正在寻求这样做。 MobileIron开发支持为我们提供了这段代码,它通过MobileIron的Core Config技术导入AppConnect Wrapper提供的证书。

它不漂亮,但由于它是由他们提供的,我不允许修改它。它虽然有效!您将其插入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;
}

构建应用程序后,请让MobileIron管理员“包装”应用程序,以便它可以使用AppConnect。完成此操作并部署包装的应用程序以通过MobileIron测试用户后,设置一个Core Config,其中包含特定于已配置用户的用户证书,并将其推送到Core Config键“kUserCert”下的配置设备。