AFSecurityPolicy这个类的最用是为了验证HTTPS证书是否正确
https=http+ssl证书
一 实例化
先从头文件看 AFSecurityPolicy中所用API来自于 <Security/Security.h>,从字面理解就可以想到安全
接下来有一个自定义的枚举值
Paste_Image.png
在看他的三个实例化方法
Paste_Image.png可以看出来后两个初始化方法都试从本地加载.cer证书,然后取出证书中的公钥存放在集合里
#pragma mark 加载某个包下所有的证书 以二进制保存在集合里面
+ (NSSet *)certificatesInBundle:(NSBundle *)bundle
{
NSArray *paths = [bundle pathsForResourcesOfType:@"cer" inDirectory:@"."];
NSMutableSet *certificates = [NSMutableSet setWithCapacity:[paths count]];
for (NSString *path in paths)
{
NSData *certificateData = [NSData dataWithContentsOfFile:path];
[certificates addObject:certificateData];
}
return [NSSet setWithSet:certificates];
}
#pragma mark - 取出所有证书中的所有公钥 放在集合里
- (void)setPinnedCertificates:(NSSet *)pinnedCertificates
{
_pinnedCertificates = pinnedCertificates;
if (pinnedCertificates)
{
NSMutableSet *mutablePinnedPublicKeys = [NSMutableSet setWithCapacity:[pinnedCertificates count]];
for (NSData *certificate in pinnedCertificates)
{
id publicKey = AFPublicKeyForCertificate(certificate);
if (!publicKey)
{
continue;
}
[mutablePinnedPublicKeys addObject:publicKey];
}
self.pinnedPublicKeys = [NSSet setWithSet:mutablePinnedPublicKeys];
} else
{
self.pinnedPublicKeys = nil;
}
}
/*
__Require_Quiet 当条件返回false时,执行标记以后的代码
__Require_noErr_Quiet 当条件抛出异常时,执行标记以后的代码
*/
// 在证书中获取公钥
static id AFPublicKeyForCertificate(NSData *certificate)
{
id allowedPublicKey = nil;
SecCertificateRef allowedCertificate;
SecPolicyRef policy = nil;
SecTrustRef allowedTrust = nil;
SecTrustResultType result;
// 1. 根据二进制的证书生成SecCertificateRef类型的证书
allowedCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificate);
// 2.allowedCertificate != NULL 如果条件不成立就跳到_out标记处
__Require_Quiet(allowedCertificate != NULL, _out);
// 3. 新建policy为X.509
policy = SecPolicyCreateBasicX509();
// 4.根据SecCertificateRef类型的证书创建SecTrustRef对象, 如果出错就跳到_out标记处
__Require_noErr_Quiet(SecTrustCreateWithCertificates(allowedCertificate, policy, &allowedTrust), _out);
// 5.校验证书的过程,同步方法 结果存在 result中
__Require_noErr_Quiet(SecTrustEvaluate(allowedTrust, &result), _out);
// 6.在SecTrustRef对象中取出公钥
allowedPublicKey = (__bridge_transfer id)SecTrustCopyPublicKey(allowedTrust);
_out:
if (allowedTrust) {
CFRelease(allowedTrust);
}
if (policy) {
CFRelease(policy);
}
if (allowedCertificate) {
CFRelease(allowedCertificate);
}
return allowedPublicKey;
}
二 验证证书是否正确
Paste_Image.png一个serverTrust是一个证书的管理对象,所有队证书操作的方法都在这个类里面
#pragma mark - 核心方法 验证证书是否正确的方法
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
forDomain:(NSString *)domain
{
if (domain &&
self.allowInvalidCertificates &&
self.validatesDomainName &&
(self.SSLPinningMode == AFSSLPinningModeNone ||
[self.pinnedCertificates count] == 0))
{
JZLog(@"In order to validate a domain name for self signed certificates, you MUST use pinning.");
return NO;
}
// 证书的策略
NSMutableArray *policies = [NSMutableArray array];
if (self.validatesDomainName)
{
//验证domain 使用SecPolicyCreateSSL函数创建验证策略, 其中第一个参数为true表示验证整个SSL证书链,
//第二个参数传入domain,用于判断整个证书链上需要验证的节点表示的那个domain是否和此处传入domain一致
[policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)];
} else
{
// 如果不需要验证domain,使用默认的BasicX509验证策略
[policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];
}
// 为serverTrust添加验证车略,即告诉服务端如何验证策略
SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);
if (self.SSLPinningMode == AFSSLPinningModeNone)
{
return self.allowInvalidCertificates || AFServerTrustIsValid(serverTrust);
} else if (!AFServerTrustIsValid(serverTrust) && !self.allowInvalidCertificates)
{
// 服务器不通过 且 不允许自创建证书
return NO;
}
// 代码能够走到这里说明两点
// 1.通过了根证书的验证 或者 allowInvalidCertificates = YES
switch (self.SSLPinningMode)
{
case AFSSLPinningModeNone:
default:
return NO;
case AFSSLPinningModeCertificate:
{ // 全部校验
NSMutableArray *pinnedCertificates = [NSMutableArray array];
for (NSData *certificateData in self.pinnedCertificates)
{
// 将二进制证书转换为 SecCertificateRef 类型证书
[pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)];
}
// 把本地的证书设为根证书,即服务器应该信任的证书
SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates);
// 校验能够信任
if (!AFServerTrustIsValid(serverTrust))
{
return NO;
}
// 取出服务器中的所有证书
NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust);
// 判断本地是否包含服务里返回的证书
for (NSData *trustChainCertificate in [serverCertificates reverseObjectEnumerator])
{
if ([self.pinnedCertificates containsObject:trustChainCertificate])
{
return YES;
}
}
return NO;
}
case AFSSLPinningModePublicKey:
{
NSUInteger trustedPublicKeyCount = 0;
NSArray *publicKeys = AFPublicKeyTrustChainForServerTrust(serverTrust);
for (id trustChainPublicKey in publicKeys)
{
for (id pinnedPublicKey in self.pinnedPublicKeys)
{
if (AFSecKeyIsEqualToKey((__bridge SecKeyRef)trustChainPublicKey, (__bridge SecKeyRef)pinnedPublicKey))
{
trustedPublicKeyCount += 1;
}
}
}
return trustedPublicKeyCount > 0;
}
}
return NO;
}
网友评论