一般情况下对于
HTTPS
,如果公司申请认证之后,客户端是不需要做什么操作。但是如果是自建证书,没有通过CA
认证的话,就需要我们代码里自己做认证。就如很早之前的12306
,打开就是不受信任的证书,那个就是自建证书。
如果服务端已经配置好了各种证书,那么
步骤2
不需要看,直接略过。验证之前需步骤5
进行设置。
1. HTTPS
双向认证过程
HTTPS双向认证过程
2. 创建CA
证书
这里的
CA
证书是不经过认证的,自己创建的一个证书
2.1 生成证书
2.1.1 创建私钥
openssl genrsa -out root/root-key.pem 1024
2.1.2 创建证书请求
openssl req -new -out root/root-req.csr -key root/root-key.pem
2.1.3 自签署证书
openssl x509 -req -in root/root-req.csr -out root/root-cert.pem -signkey root/root-key.pem -days 3650
2.1.4 将证书导出成浏览器支持的.p12格式
openssl pkcs12 -export -clcerts -in root/root-cert.pem -inkey root/root-key.pem -out root/root.p12
2.2 生成sever证书
2.2.1 创建私钥
openssl genrsa -out server/server-key.pem 1024
2.2.2 创建证书请求
openssl req -new -out server/server-req.csr -key server/server-key.pem
2.2.3 自签署证书
openssl x509 -req -in server/server-req.csr -out server/server-cert.pem -signkey server/server-key.pem -CA root/root-cert.pem -CAkey root/root-key.pem -CAcreateserial -days 3650
2.2.4 将证书导出成浏览器支持的.p12格式
openssl pkcs12 -export -clcerts -in server/server-cert.pem -inkey server/server-key.pem -out server/server.p12
2.3 生成client证书
2.3.1 创建私钥
openssl genrsa -out client/client-key.pem 1024
2.3.2 创建证书请求
openssl req -new -out client/client-req.csr -key client/client-key.pem
2.3.3 自签署证书
openssl x509 -req -in client/client-req.csr -out client/client-cert.pem -signkey client/client-key.pem -CA root/root-cert.pem -CAkey root/root-key.pem -CAcreateserial -days 3650
2.3.4 将证书导出成浏览器支持的.p12格式
openssl pkcs12 -export -clcerts -in client/client-cert.pem -inkey client/client-key.pem -out client/client.p12
3. iOS客户端设置双向认证
用的是
AFNetworking
进行双向验证
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface BJAFNetWorking : NSObject
+(AFHTTPSessionManager *) createCredentialsClient;
@end
NS_ASSUME_NONNULL_END
#import "BJAFNetWorking.h"
@implementation BJAFNetWorking
+ (AFHTTPSessionManager *)manager
{
static AFHTTPSessionManager *shareInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
shareInstance = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:BJBASEURL_KEY] sessionConfiguration:configuration];
//设置请求参数的类型:JSON
shareInstance.requestSerializer = [AFJSONRequestSerializer serializer];
//设置服务器返回结果的类型:JSON (AFJSONResponseSerializer,AFHTTPResponseSerializer)
shareInstance.responseSerializer = [AFJSONResponseSerializer serializer];
//设置请求的超时时间
shareInstance.requestSerializer.timeoutInterval = 20.0f;
//设置ContentType
shareInstance.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/html", @"text/json", @"text/plain", @"text/javascript", @"text/xml", @"image/jpeg",@"image/png", nil];
// https配置
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"Your sever cer(服务端公钥)" ofType:@"cer"];
NSData *certData = [NSData dataWithContentsOfFile:cerPath];
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:[[NSSet alloc] initWithObjects:certData, nil]];
NSSet *dataSet = [[NSSet alloc] initWithObjects:certData, nil]; //这里可以添加多个server的证书
// setPinnedCertificates 设置证书文件(可能不止一个证书)
[securityPolicy setPinnedCertificates:dataSet];
// allowInvalidCertificates 是否允许无效证书
[securityPolicy setAllowInvalidCertificates:NO];
// validatesDomainName 是否需要验证域名
[securityPolicy setValidatesDomainName:YES];
shareInstance.securityPolicy = securityPolicy;
});
return shareInstance;
}
/*
*
**
* 创建服务器信任客户端的认证条件
**
*/
+(AFHTTPSessionManager *) createCredentialsClient
{
__block AFHTTPSessionManager * manager = [BJAFNetWorking manager];
[manager setSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession*session, NSURLAuthenticationChallenge *challenge, NSURLCredential *__autoreleasing*_credential) {
NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
__autoreleasing NSURLCredential *credential =nil;
if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
if([manager.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
if(credential) {
disposition =NSURLSessionAuthChallengeUseCredential;
} else {
disposition =NSURLSessionAuthChallengePerformDefaultHandling;
}
} else {
disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
}
} else {
// client authentication
SecIdentityRef identity = NULL;
SecTrustRef trust = NULL;
NSString *p12 = [[NSBundle mainBundle] pathForResource:@"Your client p12"ofType:@"p12"];
NSFileManager *fileManager =[NSFileManager defaultManager];
if(![fileManager fileExistsAtPath:p12])
{
NSLog(@"client.p12:not exist");
}
else
{
NSData *PKCS12Data = [NSData dataWithContentsOfFile:p12];
if ([BJAFNetWorking extractIdentity:&identity andTrust:&trust fromPKCS12Data:PKCS12Data])
{
SecCertificateRef certificate = NULL;
SecIdentityCopyCertificate(identity, &certificate);
const void*certs[] = {certificate};
CFArrayRef certArray =CFArrayCreate(kCFAllocatorDefault, certs,1,NULL);
credential =[NSURLCredential credentialWithIdentity:identity certificates:(__bridge NSArray*)certArray persistence:NSURLCredentialPersistencePermanent];
disposition =NSURLSessionAuthChallengeUseCredential;
}
}
}
*_credential = credential;
return disposition;
}];
return manager;
}
/**
**加载PKCS12证书,pfx或p12
**
**/
+(BOOL)extractIdentity:(SecIdentityRef*)outIdentity andTrust:(SecTrustRef *)outTrust fromPKCS12Data:(NSData *)inPKCS12Data {
OSStatus securityError = errSecSuccess;
//client certificate password
NSDictionary*optionsDictionary = [NSDictionary dictionaryWithObject:@"Your client p12 password(密码)"
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;
const void*tempTrust =NULL;
tempTrust = CFDictionaryGetValue(myIdentityAndTrust,kSecImportItemTrust);
*outTrust = (SecTrustRef)tempTrust;
} else {
NSLog(@"Failedwith error code %d",(int)securityError);
return NO;
}
return YES;
}
@end
4. 使用
在需要初始化AFHTTPSessionManager
的地方使用如下代码进行初始化
[BJAFNetWorking createCredentialsClient]
5. 补充说明
5.1 对于cer
证书
cer
证书,常用名称为域名形式
5.2 info.plist
文件配置
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>xxxx.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSExceptionMinimumTLSVersion</key>
<string>TLSv1.0</string>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>
网友评论