AFSecurityPolicy 安全策略

https 的基础内容,提前预习

AFSecurityPolicy 注释

PS: 小结

  1. AFSSLPinningModeCertificate :证书模式 1)判断信任链上的公钥是否有交集 2)判断授权是否有效等信息
  2. AFSSLPinningModePublicKey : 公钥模式:只是 判断信任链上的公钥是否有交集
// 这个方法就是简单的判断两个对象是否相等
static BOOL AFSecKeyIsEqualToKey(SecKeyRef key1, SecKeyRef key2) {
    return [(__bridge id)key1 isEqual:(__bridge id)key2];
}

通过证书数据获取公钥

static id AFPublicKeyForCertificate(NSData *certificate) {
    id allowedPublicKey = nil;

 // 这几个对象要理解清楚
    SecCertificateRef allowedCertificate; // 允许证书
    SecPolicyRef policy = nil; // 安全策略
    SecTrustRef allowedTrust = nil; // 信任上下文
    SecTrustResultType result; // 信任结果

  // 通过证书数据获取一个证书对象
    allowedCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificate);
    __Require_Quiet(allowedCertificate != NULL, _out); 

    policy = SecPolicyCreateBasicX509(); // X509的格式策略
    __Require_noErr_Quiet(SecTrustCreateWithCertificates(allowedCertificate, policy, &allowedTrust), _out);
 // 证书数据、策略 创建一个信任对象

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
    __Require_noErr_Quiet(SecTrustEvaluate(allowedTrust, &result), _out); 
// 对信任对象进行评估, 是否是信任的,如果信任的
#pragma clang diagnostic pop

// 如果信任的就获取公钥返回
    allowedPublicKey = (__bridge_transfer id)SecTrustCopyPublicKey(allowedTrust); 

_out:
    if (allowedTrust) {
        CFRelease(allowedTrust);
    }

    if (policy) {
        CFRelease(policy);
    }

    if (allowedCertificate) {
        CFRelease(allowedCertificate);
    }

    return allowedPublicKey;
}
//服务器信任是否有效
 // 传入的是服务器的信任对象serverTrust,, 其实就是证书的信任对象
static BOOL AFServerTrustIsValid(SecTrustRef serverTrust) {
    BOOL isValid = NO;
    SecTrustResultType result;
    NSError *error;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
    __Require_noErr_Quiet(SecTrustEvaluate(serverTrust, &result), _out);
//    检测信任对象的结果
#pragma clang diagnostic pop

    isValid = (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed);
_out:
    return isValid;
}
// 获取一个证书的信任链
static NSArray * AFCertificateTrustChainForServerTrust(SecTrustRef serverTrust) {
    CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust);  // 证书(链)的数目
    NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:(NSUInteger)certificateCount]; //数据

    for (CFIndex i = 0; i < certificateCount; i++) {
        SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i);
        // 通过所以,获取帧数的数据
        [trustChain addObject:(__bridge_transfer NSData *)SecCertificateCopyData(certificate)];
    }

    return [NSArray arrayWithArray:trustChain]; 
}
//  获取信任的公钥链
static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) {
    SecPolicyRef policy = SecPolicyCreateBasicX509(); // X509格式的安全策略
    CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust); // 证书数目
    NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:(NSUInteger)certificateCount]; //信任链
    for (CFIndex i = 0; i < certificateCount; i++) { //  通过遍历,获取证书链中的公钥链
        SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i); // 获取信任证书
        SecCertificateRef someCertificates[] = {certificate}; // 证书
        CFArrayRef certificates = CFArrayCreate(NULL, (const void **)someCertificates, 1, NULL); // 证书

        SecTrustRef trust;
        __Require_noErr_Quiet(SecTrustCreateWithCertificates(certificates, policy, &trust), _out);
        SecTrustResultType result;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        __Require_noErr_Quiet(SecTrustEvaluate(trust, &result), _out);
#pragma clang diagnostic pop
        [trustChain addObject:(__bridge_transfer id)SecTrustCopyPublicKey(trust)]; 

    _out:
        if (trust) {
            CFRelease(trust);
        }

        if (certificates) {
            CFRelease(certificates);
        }

        continue;
    }
    CFRelease(policy);

    return [NSArray arrayWithArray:trustChain];
}


AFSecurityPolicy 对象


 // 获取bundle下面的证书
+ (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];
}

// 默认安全策略
+ (instancetype)defaultPolicy {
    AFSecurityPolicy *securityPolicy = [[self alloc] init];
    securityPolicy.SSLPinningMode = AFSSLPinningModeNone;
    return securityPolicy;
}

// 定位模式的策略
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode {
    NSSet <NSData *> *defaultPinnedCertificates = [self certificatesInBundle:[NSBundle mainBundle]]; // 证书的数据
    return [self policyWithPinningMode:pinningMode withPinnedCertificates:defaultPinnedCertificates];
}

// 获取策略, 定位模式、 定位证书
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode withPinnedCertificates:(NSSet *)pinnedCertificates {
    AFSecurityPolicy *securityPolicy = [[self alloc] init];
    securityPolicy.SSLPinningMode = pinningMode;
    [securityPolicy setPinnedCertificates:pinnedCertificates]; 
    return securityPolicy;
}

- (instancetype)init {
    self = [super init];
    if (!self) {
        return nil;
    }

    self.validatesDomainName = YES; // 有效的域名

    return self;
}

// 设置定位证书
// 其实就是设置公钥
- (void)setPinnedCertificates:(NSSet *)pinnedCertificates {
    _pinnedCertificates = pinnedCertificates;

    if (self.pinnedCertificates) { // 定位证书
        NSMutableSet *mutablePinnedPublicKeys = [NSMutableSet setWithCapacity:[self.pinnedCertificates count]];
        for (NSData *certificate in self.pinnedCertificates) {
            id publicKey = AFPublicKeyForCertificate(certificate); // 获取证书的公钥
            if (!publicKey) {
                continue;
            }
            [mutablePinnedPublicKeys addObject:publicKey];
        }
        self.pinnedPublicKeys = [NSSet setWithSet:mutablePinnedPublicKeys];
    } else {
        self.pinnedPublicKeys = nil;
    }
}

*重点方法*

// serverTrust 服务器的信任对象
// domain : 域名
// 遍历从当前的所有证书中获取证书
- (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)];
      // 域名有效, 通过域名创建SSL验证
    } else {
        [policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];   //  X509 策略
    }

    SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies); // 设置信任对象

    if (self.SSLPinningMode == AFSSLPinningModeNone) {
        // 这个服务器判断有效
        return self.allowInvalidCertificates || AFServerTrustIsValid(serverTrust);
    } else if (!self.allowInvalidCertificates && !AFServerTrustIsValid(serverTrust)) {
        return NO;
    }

    switch (self.SSLPinningMode) {
        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;
                }
            }
            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;
        }
        default:
            return NO;
    }
    return NO;
}

NSCoding与NSSecureCoding相比于NSSecureCoding 更安全。防止替换攻击,保证你读到的数据正是你写入的数据

推荐阅读更多精彩内容