0%

iOS 配置认证证书

  • 不支持 .crt

解决:转换成 .cer 格式。

1
openssl x509 -in xxx.crt -inform PEM -out xxx.cer -outform DER
  • 只支持二进制证书,不支持 base64 证书。

若用文本编辑器打开的证书是长这样的:

1
2
3
-----BEGIN CERTIFICATE-----
MIIGCDCCA/CgAw……
-----END CERTIFICATE-----

iOS 不支持 PEM 格式的证书,需要转换成 DER 二进制格式。

原理:将文本中的 base64 String 解 base64,得出的 data 再转 string。

最保险方法:

使用系统的钥匙串访问,导入证书,再导出即可。

使用代码支持 PEM 证书

安卓是直接支持 PEM 格式证书,为了兼容 iOS 以及减少证书文件的维护成本,在 iOS 端,可以通过代码从解密后的 PEM 证书中抽取格式支持的证书二进制数据。

PEM,Privacy Enhanced Mail,一般为文本格式,以 -----BEGIN... 开头,以 -----END... 结尾。中间的内容是 BASE64 编码。这种格式可以保存证书和私钥,有时我们也把PEM 格式的私钥的后缀改为 .key 以区别证书与私钥。

可见 PEM 证书是个文本,且既然有 BEGIN END 包裹,那么可能会有多个证书。所以可以给 NSData 增加一个扩展:

1
@property (nonatomic, strong, readonly) NSArray<NSData *> *tool_pemBins;

实现也很简单,使用正则表达式析出 BEGIN END 包裹的内容,去除换行,然后 BASE64 解码。

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
// NSData+Tool
- (NSArray<NSData *> *)tool_pemBins {
NSMutableArray *array = NSMutableArray.array;

NSString *string = [[NSString alloc] initWithData:self encoding:NSUTF8StringEncoding];
for (NSString *substring in [string tool_substringsMatchedRx:@"^-*BEGIN \\w*-*$([\\s\\S]*)^-*END \\w*-*$"]) {
NSString *content = substring;
content = [content stringByReplacingOccurrencesOfString:@"\n" withString:@""];
NSData *data = [[NSData alloc] initWithBase64EncodedString:content options:0];
[array addObject:data];
}

return array.copy;
}

// NSString+Tool
- (NSRegularExpression *)tool_rx {
NSRegularExpressionOptions options = NSRegularExpressionCaseInsensitive | NSRegularExpressionAnchorsMatchLines;
return [NSRegularExpression regularExpressionWithPattern:self options:options error:NULL];
}
- (NSArray<NSString *> *)tool_substringsMatchedRx:(NSString *)rx {
NSMutableArray *array = NSMutableArray.array;
NSArray *results = [rx.tool_rx matchesInString:self options:0 range:NSMakeRange(0, self.length)];
for (NSTextCheckingResult *result in results) {
for (int i = 1; i < result.numberOfRanges; i++) {
NSRange range = [result rangeAtIndex:i];
if (range.location == NSNotFound || range.length == 0) continue;
[array addObject:[self substringWithRange:range]];
}
}
return array.copy;
}

做这个的时候,时间都花在正则表达式的匹配上了,因为 iOS 的正则表达式跟 sublime text 编辑器的正则表达式搜索有细微的差别,语法似乎也支持得不够全面,因此需要在 iOS 上做不断修整。

参考资料

欢迎关注我的其它发布渠道