变更记录

序号 录入时间 录入人 备注
1 2016-03-08 Alfred Jiang -

方案名称

网络 - iOS 访问 HTTPS SSL 和 TLS 双向加密

关键字

网络 \ HTTPS \ SSL \ TLS \ MKNetworkit \ AFNetworking

需求场景

  1. 访问 HTTPS 并且使用 TLS 加密的服务器。

参考链接

  1. 标哥的技术博客 - iOS访问HTTPS SSL和TLS双向加密
  2. 简书 - HTTPS接口加密和身份认证

详细内容

使用 MKNetworkit 实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
- (void)testClientCertificate {
SecIdentityRef identity = NULL;
SecTrustRef trust = NULL;
NSString *p12 = [[NSBundle mainBundle] pathForResource:@"testClient" ofType:@"p12"];
NSData *PKCS12Data = [NSData dataWithContentsOfFile:p12];

[[self class] extractIdentity:&identity andTrust:&trust fromPKCS12Data:PKCS12Data];

NSString *url = @"https://218.244.131.231/ManicureShop/api/order/pay/%@";
NSDictionary *dic = @{@"request" : @{
@"orderNo" : @"1409282102222110030643",
@"type" : @(2)
}
};

_signString = nil;
NSData *postData = [NSJSONSerialization dataWithJSONObject:dic
options:NSJSONWritingPrettyPrinted
error:nil];
NSString *sign = [self signWithSignKey:@"test" params:dic];
NSMutableData *body = [postData mutableCopy];
NSLog(@"%@", [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding]);
url = [NSString stringWithFormat:url, sign];

MKNetworkEngine *engine = [[MKNetworkEngine alloc] initWithHostName:@"218.244.131.231"];
NSString *path = [NSString stringWithFormat:@"/ManicureShop/api/order/pay/%@", sign];
MKNetworkOperation *op = [engine operationWithPath:path params:dic httpMethod:@"POST" ssl:YES];
op.postDataEncoding = MKNKPostDataEncodingTypeJSON; // 传JOSN

// 这个是app bundle 路径下的自签证书
op.clientCertificate = [[[NSBundle mainBundle] resourcePath]
stringByAppendingPathComponent:@"testClient.p12"];
// 这个是自签证书的密码
op.clientCertificatePassword = @"testHttps";

// 由于自签名的证书是需要忽略的,所以这里需要设置为YES,表示允许
op.shouldContinueWithInvalidCertificate = YES;
[op addCompletionHandler:^(MKNetworkOperation *completedOperation) {
NSLog(@"%@", completedOperation.responseJSON);
} errorHandler:^(MKNetworkOperation *completedOperation, NSError *error) {
NSLog(@"%@", [error description]);
}];

[engine enqueueOperation:op];
return;
}

// 下面这段代码是提取和校验证书的数据的
+ (BOOL)extractIdentity:(SecIdentityRef *)outIdentity
andTrust:(SecTrustRef*)outTrust
fromPKCS12Data:(NSData *)inPKCS12Data {
OSStatus securityError = errSecSuccess;

// 证书密钥
NSDictionary *optionsDictionary = @{@"testHttps": (__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(@"Failed with error code %d",(int)securityError);
return NO;
}
return YES;
}
使用 AFNetworking 实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
- (void)testClientCertificate {
SecIdentityRef identity = NULL;
SecTrustRef trust = NULL;
NSString *p12 = [[NSBundle mainBundle] pathForResource:@"testClient" ofType:@"p12"];
NSData *PKCS12Data = [NSData dataWithContentsOfFile:p12];

[[self class] extractIdentity:&identity andTrust:&trust fromPKCS12Data:PKCS12Data];

NSString *url = @"https://218.244.131.231/ManicureShop/api/order/pay/%@";
NSDictionary *dic = @{@"request" : @{
@"orderNo" : @"1409282102222110030643",
@"type" : @(2)
}
};

_signString = nil;
NSData *postData = [NSJSONSerialization dataWithJSONObject:dic
options:NSJSONWritingPrettyPrinted
error:nil];
NSString *sign = [self signWithSignKey:@"test" params:dic];
NSMutableData *body = [postData mutableCopy];
NSLog(@"%@", [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding]);
url = [NSString stringWithFormat:url, sign];

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
[manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithArray:@[@"application/json",
@"text/plain"]];
manager.securityPolicy = [self customSecurityPolicy];

[manager POST:url parameters:dic success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"JSON: %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {

NSLog(@"Error: %@", error);
}];
}

// 下面这段代码是处理SSL安全性问题的:
/**** SSL Pinning ****/
- (AFSecurityPolicy*)customSecurityPolicy {
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"testClient" ofType:@"cer"];
NSData *certData = [NSData dataWithContentsOfFile:cerPath];
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy defaultPolicy];
[securityPolicy setAllowInvalidCertificates:YES];
[securityPolicy setPinnedCertificates:@[certData]];
[securityPolicy setSSLPinningMode:AFSSLPinningModeCertificate];
/**** SSL Pinning ****/
return securityPolicy;
}

效果图

(无)

备注

(无)