2016-08-01 122 views
2

哪些方法可以在我的iOS應用程序中實現SSL證書驗證? 目前我正在做的是將遠程SSL證書數據與本地證書數據進行比較。但是這種方法的缺點是每次我們改變遠程證書時,我們都需要從我們的應用中的客戶端請求更新,這是非常煩人的。 而不是比較數據是否有另一種方法來執行SSL證書驗證? 這是我在didReceiveChallenge中的代碼。NSURLSession中的SSL證書驗證

-(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler { 


SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; 
     SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, 0); //index 0 indicates leaf certificate . 

NSMutableArray *policies = [NSMutableArray array]; 
     [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)challenge.protectionSpace.host)]; 
     SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies); 


     SecTrustResultType result; 
     SecTrustEvaluate(serverTrust, &result); 
     BOOL certificateIsValid = (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed); //Unspecified-4 ,Proceed-1 


     NSData *remoteCertificateData = CFBridgingRelease(SecCertificateCopyData(certificate)); 


     NSData *localCertificateData = [NSData dataWithContentsOfFile: self.nsurl_pathToCertificate ]; 


     if ([remoteCertificateData isEqualToData:localCertificateData ]&& certificateIsValid) { 
     NSLog(@"Certificate data are same "); 
     NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; 
     completionHandler(NSURLSessionAuthChallengeUseCredential, credential); 
     } 
     else{ 
     NSLog(@"Certificate data are different or invalid certificate"); 
     completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, NULL); 
     } 
    } 

哪裏self.nsurl_pathToCertificate是通向我的本地證書。

回答

1

不同的方式做到這一點是使用Public keys鋼釘關鍵)爲進行比較,顯得更爲wiki

起初,你加載的所有證書,你有什麼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]; 
} 

+ (NSSet *)defaultPinnedCertificates { 
    static NSSet *_defaultPinnedCertificates = nil; 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     NSBundle *bundle = [NSBundle bundleForClass:[self class]]; 
     _defaultPinnedCertificates = [self certificatesInBundle:bundle]; 
    }); 

    return _defaultPinnedCertificates; 
} 

_pinnedCertificates = [YOUR_CLASS defaultPinnedCertificates]; 

並從中創建public key

- (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; 
    } 
} 

static id AFPublicKeyForCertificate(NSData *certificate) { 
    id allowedPublicKey = nil; 
    SecCertificateRef allowedCertificate; 
    SecCertificateRef allowedCertificates[1]; 
    CFArrayRef tempCertificates = nil; 
    SecPolicyRef policy = nil; 
    SecTrustRef allowedTrust = nil; 
    SecTrustResultType result; 

    allowedCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificate); 

    allowedCertificates[0] = allowedCertificate; 
    tempCertificates = CFArrayCreate(NULL, (const void **)allowedCertificates, 1, NULL); 

    policy = SecPolicyCreateBasicX509(); 
    SecTrustCreateWithCertificates(tempCertificates, policy, &allowedTrust); 
    SecTrustEvaluate(allowedTrust, &result); 

    allowedPublicKey = (__bridge_transfer id)SecTrustCopyPublicKey(allowedTrust); 

    if (allowedTrust) { 
     CFRelease(allowedTrust); 
    } 

    if (policy) { 
     CFRelease(policy); 
    } 

    if (tempCertificates) { 
     CFRelease(tempCertificates); 
    } 

    if (allowedCertificate) { 
     CFRelease(allowedCertificate); 
    } 

    return allowedPublicKey; 
} 

- (void)URLSession:(NSURLSession *)session 
       task:(NSURLSessionTask *)task 
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge 
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler 

方法檢查

NSMutableArray *policies = [NSMutableArray array]; 
    [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)]; 

    SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies); 
    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; 


static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) { 
    SecPolicyRef policy = SecPolicyCreateBasicX509(); 
    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; 
     SecTrustCreateWithCertificates(certificates, policy, &trust); 

     SecTrustResultType result; 
     SecTrustEvaluate(trust, &result); 

     [trustChain addObject:(__bridge_transfer id)SecTrustCopyPublicKey(trust)]; 

     if (trust) { 
      CFRelease(trust); 
     } 

     if (certificates) { 
      CFRelease(certificates); 
     } 

     continue; 
    } 
    CFRelease(policy); 

    return [NSArray arrayWithArray:trustChain]; 
} 

static BOOL AFSecKeyIsEqualToKey(SecKeyRef key1, SecKeyRef key2) { 
    return [(__bridge id)key1 isEqual:(__bridge id)key2]; 
} 

此代碼形式AFNetwking

對於這種方式,您無需更新本地證書,如果它在遠程服務器

+0

更新你能更具體一些嗎?你在哪裏獲得固定證書?您已將其作爲參數傳遞給setPinnedCertificates方法。 – iPhoneDeveloper

+0

你的固定證書包(本地證書)請閱讀答案的最高句子 – iSashok

+0

你能舉個例子嗎?你怎麼稱呼那個方法?我們在哪裏獲得固定證書? – iPhoneDeveloper