本文主要是为了afnetworking下配置https证书验证。html
最近公司另外一个APP要作SSL自定义验证,参考了另外一个APP已由其余同事写好的代码,顺便总结一下相关知识。ios
参考1:http://blog.csdn.net/dr19901106/article/details/50294393算法
HTTPS是运行在 TLS/SSL 之上的 HTTP,与普通的 HTTP 相比,在数据传输的安全性上有很大的提高。要了解它安全性的巧妙之处,须要先简单地了解对称加密和非对称加密的区别!服务器
对称加密只有一个密钥,加密和解密都用这个密钥;session
非对称加密有公钥和私钥,私钥加密后的内容只有公钥才能解密,公钥加密的内容只有私钥才能解密。app
为了提升安全性,咱们经常使用的作法是使用对称加密的手段加密数据。但是只使用对称加密的话,双方通讯的开始总会以明文的方式传输密钥。那么从一开始这个密钥就泄露了,谈不上什么安全。因此 TLS/SSL 在握手的阶段,结合非对称加密的手段,保证只有通讯双方才知道对称加密的密钥。大概的流程以下:加密
X.509 应该是比较流行的 SSL 数字证书标准,包含(但不限于)如下的字段:lua
字段 | 值说明 |
---|---|
对象名称(Subject Name) | 用于识别该数字证书的信息 |
共有名称(Common Name) | 对于客户证书,一般是相应的域名 |
证书颁发者(Issuer Name) | 发布并签署该证书的实体的信息 |
签名算法(Signature Algorithm) | 签名所使用的算法 |
序列号(Serial Number) | 数字证书机构(Certificate Authority, CA)给证书的惟一整数,一个数字证书一个序列号 |
生效期(Not Valid Before) | (`・ω・´) |
失效期(Not Valid After) | (╯°口°)╯(┴—┴ |
公钥(Public Key) | 可公开的密钥 |
签名(Signature) | 经过签名算法计算证书内容后获得的数据,用于验证证书是否被篡改 |
数字证书的生成是分层级的,下一级的证书须要其上一级证书的私钥签名。 因此后者是前者的证书颁发者,也就是说上一级证书的 Subject Name 是其下一级证书的 Issuer Name。url
在获得证书申请者的一些必要信息(对象名称,公钥私钥)以后,证书颁发者经过 SHA-256 哈希获得证书内容的摘要,再用本身的私钥给这份摘要加密,获得数字签名。综合已有的信息,生成分别包含公钥和私钥的两个证书。
- (void)setSessionDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * _Nullable __autoreleasing * _Nullable credential))block;
数值 | 中文说明 |
---|---|
NSURLSessionAuthChallengeUseCredential = 0, | 使用证书 |
NSURLSessionAuthChallengePerformDefaultHandling = 1, | 忽略证书(默认的处理方式) |
NSURLSessionAuthChallengeCancelAuthenticationChallenge = 2, | 忽略书证, 并取消此次请求 |
NSURLSessionAuthChallengeRejectProtectionSpace = 3, | 拒绝当前这一次, 下一次再询问 |
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]; securityPolicy.allowInvalidCertificates = NO;//是否容许使用自签名证书 securityPolicy.validatesDomainName = YES;//是否须要验证域名,默认YES [manager setSecurityPolicy:securityPolicy];
+ (AFHTTPSessionManager *)addHeaderForSignWithRequestURL:(NSString *)requestURL mathod:(NSString *)method needToDecrypt:(BOOL)needToDecrypt { static AFHTTPSessionManager *manager = nil; static dispatch_once_t oneToken; dispatch_once(&oneToken, ^{ manager = [[AFHTTPSessionManager manager] initWithBaseURL:[NSURL URLWithString:OnLineURL]]; [manager.responseSerializer setAcceptableContentTypes:[NSSet setWithObjects: TTVNetWork_AcceptableContentType_ApplicationJson,TTVNetWork_AcceptableContentType_TextHtml, TTVNetWork_AcceptableContentType_TextJvascript,TTVNetWork_AcceptableContentType_TextJson, TTVNetWork_AcceptableContentType_TextPlain,TTVNetWork_AcceptableContentType_urlencoded,nil]]; manager.requestSerializer = [AFJSONRequestSerializer serializer]; manager.responseSerializer = [AFJSONResponseSerializer serializer]; // 设置超时时间 [manager.requestSerializer willChangeValueForKey:TTVNewWork_timeoutInterValKey]; manager.requestSerializer.timeoutInterval = TTVNetWork_TimeoutInterval; [manager.requestSerializer didChangeValueForKey:TTVNewWork_timeoutInterValKey]; // DeviceID 0. [manager.requestSerializer setValue:NetworkOptionShareIntance.prefixDeviceID forHTTPHeaderField:TTVNetWork_DeviceIDKey]; // // SSL Pinning // [manager setSecurityPolicy:[self customSecurityPolicy]]; AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]; securityPolicy.allowInvalidCertificates = NO;//是否容许使用自签名证书 securityPolicy.validatesDomainName = YES;//是否须要验证域名,默认YES [manager setSecurityPolicy:securityPolicy]; // 自定义验证证书 [manager setSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential *__autoreleasing *_credential) { BOOL isServerTrust = NO;//全部证书验证经过 BOOL isCertRootTrust = NO;//根证书验证经过 BOOL isCertSecondTrust = NO;//二级证书验证经过 BOOL isCertClientTrust = NO;//最后一级,本地证书验证经过 //取得服务器返回的三级证书 SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust]; //遍历服务器返回的证书 CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust); for (CFIndex i = certificateCount - 1; i >= 0; i--) { SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i); NSString *subjectSummary = (__bridge_transfer NSString *)SecCertificateCopySubjectSummary(certificate); //证书NSData转为NSString CFDataRef certData = SecCertificateCopyData(certificate); NSString *certificateBase64String = [(__bridge_transfer NSData *)certData base64EncodedStringWithOptions:0]; //比较本地保存的一级和二级证书NSString if (i == certificateCount - 1) {//一级根证书 if ([certificateBase64String isEqualToString:certStringForRoot]) { isCertRootTrust = YES; } } else if (i == certificateCount - 2) {//第二级证书 if ([certificateBase64String isEqualToString:certStringForSecondLevel]) { isCertSecondTrust = YES; } } else if (i == 0) {//第三级:要部分验证的本地证书 // //服务器证书的颁发机构序列号 // CFDataRef issuerSequenceData = SecCertificateCopyNormalizedIssuerSequence(certificate);//iOS 10.3 后,才能使用此方法 // NSString *issuerSequenceBase64String = [(__bridge_transfer NSData *)issuerSequenceData base64EncodedStringWithOptions:0]; //获取本地证书 NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"itouchtv_app" ofType:@"cer"]; NSData *certData = [NSData dataWithContentsOfFile:cerPath]; SecCertificateRef certificateLocal = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certData); //域名 NSString *subjectSummaryLocal = (__bridge_transfer NSString *)SecCertificateCopySubjectSummary(certificateLocal); // //颁发机构序列号 // CFDataRef issuerSequenceDataLocal = SecCertificateCopyNormalizedIssuerSequence(certificateLocal); // NSString *issuerSequenceBase64StringLocal = [(__bridge_transfer NSData *)issuerSequenceDataLocal base64EncodedStringWithOptions:0]; //验证 // if ([subjectSummary isEqualToString:subjectSummaryLocal] // && [issuerSequenceBase64String isEqualToString:issuerSequenceBase64StringLocal]) // { // isCertClientTrust = YES; // } if ([subjectSummary isEqualToString:subjectSummaryLocal]) { isCertClientTrust = YES; } } } DLog(@"一级根证书是否验证经过:%@,第二级证书是否验证经过:%@,第三级本地证书是否验证经过:%@", @(isCertRootTrust), @(isCertSecondTrust), @(isCertClientTrust)); //判断全部证书是否验证经过 if (isCertRootTrust && isCertSecondTrust && isCertClientTrust) { isServerTrust = YES; } NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling; __autoreleasing NSURLCredential *credential = nil; if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { // if ([manager.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) { if (isServerTrust) {//使用本身的判断逻辑 credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; if (credential) { disposition = NSURLSessionAuthChallengeUseCredential; } else { disposition = NSURLSessionAuthChallengePerformDefaultHandling; } } else { disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge; } } else { disposition = NSURLSessionAuthChallengePerformDefaultHandling; } return disposition; }]; [TTVPlayerMoniter sharedMointerManager]; }); // USERID & Authorization if ([TTVUserInfo sharedTTVUserInfo].isLogin) {//1. [manager.requestSerializer setValue:[TTVUserInfo sharedTTVUserInfo].currentUser.userId forHTTPHeaderField:TTVNetWork_UserIDKey]; NSString *authorization = [NSString stringWithFormat:@"Bearer %@",[TTVUserInfo sharedTTVUserInfo].currentUser.jwt];//2. [manager.requestSerializer setValue:authorization forHTTPHeaderField:TTVNetWork_AuthorizationKey]; }else { [manager.requestSerializer setValue:NetworkOptionShareIntance.prefixDeviceID forHTTPHeaderField:TTVNetWork_DeviceIDKey]; [manager.requestSerializer setValue:nil forHTTPHeaderField:TTVNetWork_UserIDKey]; [manager.requestSerializer setValue:nil forHTTPHeaderField:TTVNetWork_AuthorizationKey]; } return manager; }
原文:http://raychow.linkfun.top/2017/12/15/archives/1_ios/HTTPS_Certificate_Certification/index/