以下是AFN內(nèi)AFSecurityPolicy
的evaluateServerTrust:forDomain:
方法的代碼.我們看了好幾遍,覺得太繁瑣了吧!我根據(jù)我了解的AFSecurityPolicy各項屬性的功能,改寫了一個簡單的版本,還煩請各位前輩看看,這樣的改寫行不行?
- 源碼
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
forDomain:(NSString *)domain
{
if (domain && self.allowInvalidCertificates && self.validatesDomainName && (self.SSLPinningMode == AFSSLPinningModeNone || [self.pinnedCertificates count] == 0)) {
// https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/NetworkingTopics/Articles/OverridingSSLChainValidationCorrectly.html
// According to the docs, you should only trust your provided certs for evaluation.
// Pinned certificates are added to the trust. Without pinned certificates,
// there is nothing to evaluate against.
//
// From Apple Docs:
// "Do not implicitly trust self-signed certificates as anchors (kSecTrustOptionImplicitAnchors).
// Instead, add your own (self-signed) CA certificate to the list of trusted anchors."
NSLog(@"In order to validate a domain name for self signed certificates, you MUST use pinning.");
return NO;
}
NSMutableArray *policies = [NSMutableArray array];
if (self.validatesDomainName) {
[policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)];
} else {
[policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];
}
SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);
if (self.SSLPinningMode == AFSSLPinningModeNone) {
return self.allowInvalidCertificates || AFServerTrustIsValid(serverTrust);
} else if (!AFServerTrustIsValid(serverTrust) && !self.allowInvalidCertificates) {
return NO;
}
switch (self.SSLPinningMode) {
case AFSSLPinningModeNone:
default:
return NO;
case AFSSLPinningModeCertificate: {
NSMutableArray *pinnedCertificates = [NSMutableArray array];
for (NSData *certificateData in self.pinnedCertificates) {
[pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)];
}
SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates);
if (!AFServerTrustIsValid(serverTrust)) {
return NO;
}
// obtain the chain after being validated, which *should* contain the pinned certificate in the last position (if it's the Root CA)
NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust);
for (NSData *trustChainCertificate in [serverCertificates reverseObjectEnumerator]) {
if ([self.pinnedCertificates containsObject:trustChainCertificate]) {
return YES;//zc read:有一個對得上就,代表驗證成功
}
}
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;//zc read:有一個對得上就,代表驗證成功
}
}
return NO;
}
- 屬性認(rèn)識
/*
1.SSLPinningMode 模式:默認(rèn)==>AFSSLPinningModeNone
AFSSLPinningModeNone==>不進(jìn)行驗證
AFSSLPinningModePublicKey==>用本地的證書的公鑰進(jìn)行驗證
AFSSLPinningModeCertificate==>用本地的證書進(jìn)行驗證
*/
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
//2.allowInvalidCertificates 是否允許自簽名:默認(rèn)==>NO
securityPolicy.allowInvalidCertificates = NO;
//3.validatesDomainName 是否驗證域名:默認(rèn)==>YES
securityPolicy.validatesDomainName = NO;
//4.pinnedCertificates 本地導(dǎo)入的證書:默認(rèn)==>app包內(nèi)所有的.cer全會被添加進(jìn)來
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"server" ofType:@"cer"];
NSData *certData = [NSData dataWithContentsOfFile:cerPath];
securityPolicy.pinnedCertificates = [NSSet setWithObject:certData];
- 改寫
- (BOOL)zc_evaluateServerTrust:(SecTrustRef)serverTrust
forDomain:(NSString *)domain
{
/*part1:*/
//驗證簽名,卻沒有簽名 返回NO
if (self.validatesDomainName && domain == nil) {
return NO;
}
//驗證證書或公鑰 卻沒有導(dǎo)入證書 返回NO
if (self.SSLPinningMode != AFSSLPinningModeNone && self.pinnedCertificates.count <= 0) {
return NO;
}
/*part2:*/
//設(shè)置驗證策略
NSMutableArray *policies = [NSMutableArray array];
if (self.validatesDomainName) {
[policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)];
} else {
[policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];
}
SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);
/*part3:*/
//做分支判斷
if (self.SSLPinningMode == AFSSLPinningModeNone){
return self.allowInvalidCertificates || AFServerTrustIsValid(serverTrust);
}else{
if (!AFServerTrustIsValid(serverTrust) && !self.allowInvalidCertificates) {
return NO;
}
if (self.SSLPinningMode == 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;//zc read:有一個對得上就,代表驗證成功
}else if (self.SSLPinningMode == AFSSLPinningModeCertificate){
NSMutableArray *pinnedCertificates = [NSMutableArray array];
for (NSData *certificateData in self.pinnedCertificates) {
[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;//zc read:有一個對得上就,代表驗證成功
}
}
}
}
return NO;
}