iOS https认证

1: AFNetworking 进行HTTPS认证

//
//  FFBaseNetwork.h
//  Temp
//
//  Created by jisa on 2019/7/30.
//  Copyright © 2019 jff. All rights reserved.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface FFBaseNetwork : NSObject

@end

NS_ASSUME_NONNULL_END
//
//  FFBaseNetwork.m
//  Temp
//
//  Created by jisa on 2019/7/30.
//  Copyright © 2019 jff. All rights reserved.
//

#import "FFBaseNetwork.h"
#import <AFNetworking/AFNetworking.h>

@interface FFBaseNetwork ()
    
@end


@implementation FFBaseNetwork

/// 进行HTTPS验证的核心代码
- (void)FF_httpsValide:(AFHTTPSessionManager *)manager {
    /*
     *SSLPinning 证书绑定 客户端保存服务器端的证书,在建立https连接时比较服务器返回的证书是否和客户端的证书一致
     *
     *
     *AFSSLPinningModeNone 像浏览器一样在系统的信任机构列表里验证服务器端返回的证书
     *
     *AFSSLPinningModePublicKey 证书绑定,只验证公钥,不验证证书的有效期
     *
     *AFSSLPinningModeCertificate 证书绑定,第一步验证域名,有效期等信息。等而不验证证书信息
     */
    
    AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
    /// 是否允许无效的证书。 自制的https证书,在Apple中属于无效证书(不信任的证书)
    policy.allowInvalidCertificates = YES;
    /// 是否验证域名。默认为YES。如果使用的域名与证书域名不一致要设置为NO。
    policy.validatesDomainName = NO;
    NSString *path = [[NSBundle mainBundle] pathForResource:@"server" ofType:@"cer"];
    NSData *data = [NSData dataWithContentsOfFile:path];
    ///
    policy.pinnedCertificates = [[NSSet alloc] initWithObjects:data, nil];
    manager.securityPolicy = policy;
    /// 质疑block
    __weak typeof(self) weakSelf = self;
    [manager setTaskDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession * _Nonnull session, NSURLSessionTask * _Nonnull task, NSURLAuthenticationChallenge * _Nonnull challenge, NSURLCredential *__autoreleasing  _Nullable * _Nullable credential) {
        __strong typeof(weakSelf) strongSelf = weakSelf;
        __autoreleasing NSURLCredential *_credential = NULL;
        NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            /// 判断是否信任服务器证书
            /// 服务器证书是否可以被信任
            if ([policy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
                _credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
                if (_credential) {
                    disposition = NSURLSessionAuthChallengeUseCredential;
                }
            }else {
                disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
            }
        }else if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodClientCertificate]) {
            /// 客户端证书验证
            /// 双向认证才会走,服务器需要验证客户端的p12证书
            NSString *path = [[NSBundle mainBundle] pathForResource:@"client" ofType:@"p12"];
            NSData *p12Data = [NSData dataWithContentsOfFile:path options:0 error:NULL];
            SecIdentityRef identity = NULL;
            SecTrustRef trust = NULL;
            
            if ([strongSelf FF_extractIdentity:&identity andTrust:&trust fromData:p12Data]) {
                SecCertificateRef certificateRef = NULL;
                SecIdentityCopyCertificate(identity, &certificateRef);
                const void *certs[] = {certificateRef};
                CFArrayRef arrayRef = CFArrayCreate(NULL, certs, 1, NULL);
                _credential = [[NSURLCredential alloc] initWithIdentity:identity certificates:(__bridge NSArray *)arrayRef persistence:NSURLCredentialPersistencePermanent];
                disposition = NSURLSessionAuthChallengeUseCredential;
            }
        }
        *credential = _credential;
        return disposition;
        
    }];
}
/// 从客户端证书中获取 SecIdentity 和 SecTrustRef。
- (BOOL)FF_extractIdentity:(SecIdentityRef *)outIdentity andTrust:(SecTrustRef *)outTrust fromData:(NSData *)data {
    NSDictionary *dic = @{(__bridge NSString *)kSecImportExportPassphrase : @"123456"};
    
    CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
    OSStatus status = SecPKCS12Import((__bridge CFDataRef)data, (__bridge CFDictionaryRef)dic, &items);
    if (status == errSecSuccess) {
        CFDictionaryRef identityAndTrust = CFArrayGetValueAtIndex(items, 0);
        const void *tempIdentity = NULL;
        tempIdentity = CFDictionaryGetValue(identityAndTrust, kSecImportItemIdentity);
        *outIdentity = (SecIdentityRef)tempIdentity;
        const void *tempTrust = CFDictionaryGetValue(identityAndTrust, kSecImportItemTrust);
        *outTrust = (SecTrustRef)tempTrust;
        return YES;
    }else {
        return NO;
    }
}
    
- (AFHTTPSessionManager *)manager {
    AFHTTPSessionManager *manager = [[AFHTTPSessionManager manager] initWithBaseURL:NULL];
    manager.requestSerializer = [AFJSONRequestSerializer serializer];
    manager.responseSerializer = [AFJSONResponseSerializer serializer];
    manager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
    manager.requestSerializer.timeoutInterval = 30;
    manager.responseSerializer.acceptableContentTypes = [[NSSet alloc] initWithObjects:@"json/text", nil];
    return manager;
}
    
@end

2: SDWebImage 中使用HTTPS如果是双向认证的话,设置客户端证书如下

  如果是自制的HTTPS证书 在 SDWebImageDownloaderOptions 中要包括 SDWebImageDownloaderAllowInvalidSSLCertificates。允许无效的证书

//
//  SDWebImageDownloader+AFNHTTPS.m
//  TongCheng
//
//  Created by jisa on 2019/7/30.
//  Copyright © 2019 jisa. All rights reserved.
//

#import "SDWebImageDownloader+AFNHTTPS.h"

@implementation SDWebImageDownloader (AFNHTTPS)
+ (void)load {
    [SDWebImageDownloader sharedDownloader].urlCredential = [self myURLCredential];
}

+ (NSURLCredential *)myURLCredential {
    SecIdentityRef identity = NULL;
    NSString *p12Path = [[NSBundle mainBundle] pathForResource:@"client" ofType:@"p12"];
    NSData *data = [NSData dataWithContentsOfFile:p12Path];
    [self extractIdentity:&identity fromPKCS12Data:data];
    SecCertificateRef certificate = NULL;
    SecIdentityCopyCertificate(identity, &certificate);
    const void *certs[] = {certificate};
    CFArrayRef cerArray = CFArrayCreate(kCFAllocatorMalloc, certs, 1, NULL);
    return [NSURLCredential credentialWithIdentity:identity certificates:(__bridge NSArray *)cerArray persistence:NSURLCredentialPersistencePermanent];
    
}


+ (BOOL)extractIdentity:(SecIdentityRef*)outIdentity fromPKCS12Data:(NSData *)inPKCS12Data {
    OSStatus securityError = errSecSuccess;
    //client certificate password
    NSDictionary*optionsDictionary = [NSDictionary dictionaryWithObject:@"tc888888"
                                                                 forKey:(__bridge id)kSecImportExportPassphrase];
    CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
    securityError = SecPKCS12Import((__bridge CFDataRef)inPKCS12Data,(__bridge CFDictionaryRef)optionsDictionary,&items);
    if(securityError == 0) {
        CFDictionaryRef myIdentityAndTrust =CFArrayGetValueAtIndex(items,0);
        const void*tempIdentity =NULL;
        tempIdentity= CFDictionaryGetValue(myIdentityAndTrust,kSecImportItemIdentity);
        *outIdentity = (SecIdentityRef)tempIdentity;
        return YES;
    } else {
        NSLog(@"Failedwith error code %d",(int)securityError);
        return NO;
    }
}
@end

 

posted @ 2019-07-30 17:41  jisa  阅读(500)  评论(0编辑  收藏  举报