- (
BOOL
)evaluateServerTrust:(
SecTrustRef
)serverTrust
forDomain:(
NSString
*)domain
{
// 当使用自建证书验证域名时,需要使用AFSSLPinningModePublicKey或者AFSSLPinningModeCertificate进行验证
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) {
//SSLPinningMode为AFSSLPinningModeNone时,allowInvalidCertificates为YES,则代表服务器任何证书都能验证通过;
如果它为NO,则需要判断此服务器证书是否是系统信任的证书
return
self
.
allowInvalidCertificates
||
AFServerTrustIsValid
(serverTrust);
} else if (!AFServerTrustIsValid(serverTrust) && !self.allowInvalidCertificates) {
// 如果服务器证书不是系统信任证书,且不允许不信任的证书通过验证则返回NO
return
NO
;
}
switch
(
self
.
SSLPinningMode
) {
case
AFSSLPinningModeNone
:
default
:
return
NO
;
case AFSSLPinningModeCertificate: {
//AFSSLPinningModeCertificate是直接将本地的证书设置为信任的根证书,然后来进行判断,并且比较本地证书的内容和
服务器证书内容是否相同,如果有一个相同则返回YES
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
;
}
}
return
NO
;
}
case
AFSSLPinningModePublicKey
: {
NSUInteger
trustedPublicKeyCount =
0
;
NSArray
*publicKeys =
AFPublicKeyTrustChainForServerTrust
(serverTrust);
//AFSSLPinningModePublicKey是通过比较证书当中公钥(PublicKey)部分来进行验证,
通过SecTrustCopyPublicKey方法获取本地证书和服务器证书,然后进行比较,如果有一个相同,则通过验证
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
;
}