
AFSecurityPolicy這個(gè)類的最用是為了驗(yàn)證HTTPS證書是否正確
https=http+ssl證書
一 實(shí)例化
先從頭文件看 AFSecurityPolicy中所用API來(lái)自于 <Security/Security.h>,從字面理解就可以想到安全
接下來(lái)有一個(gè)自定義的枚舉值

Paste_Image.png
在看他的三個(gè)實(shí)例化方法

Paste_Image.png
可以看出來(lái)后兩個(gè)初始化方法都試從本地加載.cer證書,然后取出證書中的公鑰存放在集合里
#pragma mark 加載某個(gè)包下所有的證書 以二進(jìn)制保存在集合里面
+ (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 當(dāng)條件返回false時(shí),執(zhí)行標(biāo)記以后的代碼
__Require_noErr_Quiet 當(dāng)條件拋出異常時(shí),執(zhí)行標(biāo)記以后的代碼
*/
// 在證書中獲取公鑰
static id AFPublicKeyForCertificate(NSData *certificate)
{
id allowedPublicKey = nil;
SecCertificateRef allowedCertificate;
SecPolicyRef policy = nil;
SecTrustRef allowedTrust = nil;
SecTrustResultType result;
// 1. 根據(jù)二進(jìn)制的證書生成SecCertificateRef類型的證書
allowedCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificate);
// 2.allowedCertificate != NULL 如果條件不成立就跳到_out標(biāo)記處
__Require_Quiet(allowedCertificate != NULL, _out);
// 3. 新建policy為X.509
policy = SecPolicyCreateBasicX509();
// 4.根據(jù)SecCertificateRef類型的證書創(chuàng)建SecTrustRef對(duì)象, 如果出錯(cuò)就跳到_out標(biāo)記處
__Require_noErr_Quiet(SecTrustCreateWithCertificates(allowedCertificate, policy, &allowedTrust), _out);
// 5.校驗(yàn)證書的過(guò)程,同步方法 結(jié)果存在 result中
__Require_noErr_Quiet(SecTrustEvaluate(allowedTrust, &result), _out);
// 6.在SecTrustRef對(duì)象中取出公鑰
allowedPublicKey = (__bridge_transfer id)SecTrustCopyPublicKey(allowedTrust);
_out:
if (allowedTrust) {
CFRelease(allowedTrust);
}
if (policy) {
CFRelease(policy);
}
if (allowedCertificate) {
CFRelease(allowedCertificate);
}
return allowedPublicKey;
}
二 驗(yàn)證證書是否正確

Paste_Image.png
一個(gè)serverTrust是一個(gè)證書的管理對(duì)象,所有隊(duì)證書操作的方法都在這個(gè)類里面
#pragma mark - 核心方法 驗(yàn)證證書是否正確的方法
- (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)
{
//驗(yàn)證domain 使用SecPolicyCreateSSL函數(shù)創(chuàng)建驗(yàn)證策略, 其中第一個(gè)參數(shù)為true表示驗(yàn)證整個(gè)SSL證書鏈,
//第二個(gè)參數(shù)傳入domain,用于判斷整個(gè)證書鏈上需要驗(yàn)證的節(jié)點(diǎn)表示的那個(gè)domain是否和此處傳入domain一致
[policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)];
} else
{
// 如果不需要驗(yàn)證domain,使用默認(rèn)的BasicX509驗(yàn)證策略
[policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];
}
// 為serverTrust添加驗(yàn)證車略,即告訴服務(wù)端如何驗(yàn)證策略
SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);
if (self.SSLPinningMode == AFSSLPinningModeNone)
{
return self.allowInvalidCertificates || AFServerTrustIsValid(serverTrust);
} else if (!AFServerTrustIsValid(serverTrust) && !self.allowInvalidCertificates)
{
// 服務(wù)器不通過(guò) 且 不允許自創(chuàng)建證書
return NO;
}
// 代碼能夠走到這里說(shuō)明兩點(diǎn)
// 1.通過(guò)了根證書的驗(yàn)證 或者 allowInvalidCertificates = YES
switch (self.SSLPinningMode)
{
case AFSSLPinningModeNone:
default:
return NO;
case AFSSLPinningModeCertificate:
{ // 全部校驗(yàn)
NSMutableArray *pinnedCertificates = [NSMutableArray array];
for (NSData *certificateData in self.pinnedCertificates)
{
// 將二進(jìn)制證書轉(zhuǎn)換為 SecCertificateRef 類型證書
[pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)];
}
// 把本地的證書設(shè)為根證書,即服務(wù)器應(yīng)該信任的證書
SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates);
// 校驗(yàn)?zāi)軌蛐湃? if (!AFServerTrustIsValid(serverTrust))
{
return NO;
}
// 取出服務(wù)器中的所有證書
NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust);
// 判斷本地是否包含服務(wù)里返回的證書
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;
}