iOS客户端证书和移动设备管理
我们的客户希望使用MDM(移动设备管理)解决方案(MobileIron)将客户端证书安装到公司的iOS设备上,以便将某些公司web服务的访问权限限制为仅限公司设备 MobileIron将客户端证书安装到“设置”>“常规”>“配置文件”中,这是iOS中证书的默认位置,当企业web服务为此证书提出质疑时,Safari可以使用此证书进行响应 但我需要在自定义应用程序中发生同样的事情。当我们的应用程序收到证书挑战时,我需要能够从设置>常规>配置文件中使用证书进行响应。我有使用与我们的应用程序捆绑在一起的证书以及我们的应用程序在其自己的密钥链中存储的证书进行响应的示例,但我没有在“设置”>“常规”>“配置文件”中使用安装在设备上的证书进行响应的示例 是否有人可以向我解释更多关于iOS客户端证书和移动设备管理,ios,ssl,client-certificates,mobileiron,Ios,Ssl,Client Certificates,Mobileiron,我们的客户希望使用MDM(移动设备管理)解决方案(MobileIron)将客户端证书安装到公司的iOS设备上,以便将某些公司web服务的访问权限限制为仅限公司设备 MobileIron将客户端证书安装到“设置”>“常规”>“配置文件”中,这是iOS中证书的默认位置,当企业web服务为此证书提出质疑时,Safari可以使用此证书进行响应 但我需要在自定义应用程序中发生同样的事情。当我们的应用程序收到证书挑战时,我需要能够从设置>常规>配置文件中使用证书进行响应。我有使用与我们的应用程序捆绑在一起的
nsurauthenticationchallengesender
协议方法-performDefaultHandlingForAuthenticationChallenge:
的功能?默认处理是否意味着iOS代表应用程序有效响应挑战?此响应是否包括存储在“设置”>“常规”>“配置文件”中的客户端证书
更新
如果MDM可以将客户端证书安装到应用程序密钥链中,那就太完美了。苹果技术支持人员向我指出了以下技术说明:
总之,我们想要做的是不受支持的。我刚从一个使用MobileIron的客户的现场回来,他正打算这样做。MobileIron开发支持为我们提供了这段代码,它通过MobileIron的核心配置技术导入AppConnect包装器提供的证书 这并不漂亮,但因为是他们提供的,所以我不允许修改它。不过它还是管用的!您可以将其插入AppDelegate。h:
- (NSString *)appConnectConfigChangedTo:(NSDictionary *)newConfig;
在前面的pragma标记之后,将其输入到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部署包装的应用程序以测试用户,请设置一个核心配置,获取特定于已配置用户的用户证书,并将其推送到核心配置密钥“kUserCert”下的已配置设备上。MobileIron的2.1更新解决了此问题,无需特殊代码。可以使用AppConnect配置推送X.509证书,AppConnect框架会在可以使用合格证书响应时拦截任何证书。证书可以在第一次启动时动态创建,稍后撤销,根据用户或设备自定义,不同的URL可以使用不同的证书
如果有人正在使用此页面上的代码段,请停止,它不是必需的。包装未修改的应用程序或在AppConnect框架中链接后,将MI_AC_CLIENT_CERT_1密钥添加到AppConnect配置,指向证书注册配置(即SCEP、Trust、Symantec PKI、PIV-D等)。添加带有URL(可选通配符)的MI_AC_客户端_1_规则键。没有第三步。您的应用程序现在将自动使用证书进行身份验证
详细信息请参见MobileIron的AppConnect和AppTunnel指南文档中的“从AppConnect应用到企业服务的证书身份验证”。非常有趣。我们必须尝试获得MobileIron的副本才能尝试此功能。您需要与MobileIron SDK集成吗?对于此功能,没有传统的库或SDK:MobileIron为我们提供了示例代码,我们必须使用他们的包装应用程序包装应用程序,以使AppConnect正常工作。@LewWeiHao它必须来自MobileIronOK,因此,在离开促使我提出这个问题的项目后,我无法尝试这个方法。这听起来似乎可以满足客户的需求,简化我们的应用程序。不过,“拦截身份验证挑战”这一部分让我有点困扰。这是否意味着AppConnect将成为HTTPS端点,而不是应用程序?那么AppConnect代理了流量?Brett,我不想在这里泄露我们的“秘密酱”,但请检查并使用NSURLAuthenticationMethodClientCertificate。我认为这是肯定的。我猜这适用于较新的会话,因为它们是共享的,所以您的框架可以拦截它们。