我们的任务是在我们的应用程序内部确定iOS设备上是否安装了特定的配置文件。没有公共API来检查设备上安装了哪些配置文件,但本文http://blog.markhorgan.com/?p=701描述了一种解决方法。
基本上,一个在配置文件中包含一个根CA,并在此根CA上签名第二个证书。第二个证书捆绑在应用程序中,然后对应用程序中第二个证书的信任评估将显示根CA是否存在(这意味着已安装配置文件)。
现在,我们无法篡改我们的配置文件(因为它已安装在许多设备上),但它已包含2个我们可以访问的证书:
遗憾的是,OurRootCA不仅包含在相关配置文件中,还包含在其他配置文件中(因此使用此方法检查可能会产生误报),但幸运的是OurIntermediateCA仅用于我们要检查的configurationProfile中
不幸的是,由于某些原因,如果使用由OurIntermediateCA颁发的测试SSL证书执行测试失败(它总是返回kSecTrustResultRecoverableTrustFailure)(它可以使用OurRootCA颁发的测试SSL证书)。
这是验证码:
//NSString* certPath = [[NSBundle mainBundle] pathForResource:@"TestCertificateSignedByRoot" ofType:@"cer"]; //with this cert, the validation works
NSString* certPath = [[NSBundle mainBundle] pathForResource:@"TestCertificateSignedByIntermediate" ofType:@"cer"];
NSData* certData = [NSData dataWithContentsOfFile:certPath];
SecCertificateRef cert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef) certData);
SecPolicyRef policy = SecPolicyCreateBasicX509();
SecTrustRef trust;
OSStatus err = SecTrustCreateWithCertificates((__bridge CFArrayRef) [NSArray arrayWithObject:(__bridge id)cert], policy, &trust);
// set trust anchor certificates to empty array as advised in http://stackoverflow.com/questions/7900896/sectrustevaluate-always-returns-ksectrustresultrecoverabletrustfailure-with-secp
SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef) [NSArray array]);
SecTrustSetAnchorCertificatesOnly(trust, NO);
SecTrustResultType trustResult = -1;
err = SecTrustEvaluate(trust, &trustResult);
CFRelease(trust);
CFRelease(policy);
CFRelease(cert);
switch(trustResult) {
case kSecTrustResultUnspecified:
case kSecTrustResultProceed: {
return YES;
// this is the result if TestCertificateSignedByRoot is used
break;
}
case kSecTrustResultRecoverableTrustFailure: {
return NO;
// this is the result if TestCertificateSignedByIntermediate is used
break;
}
default: {
return NO;
break;
}
}
因此,该技术似乎有效 - 用户钥匙串中的(自签名)rootCA用于验证我们的测试证书。但是,如果检查中间CA,则测试始终返回kSecTrustResultRecoverableTrustFailure。这可能是什么问题以及如何调试?