解决:转换成 .cer
格式。
1
| openssl x509 -in xxx.crt -inform PEM -out xxx.cer -outform DER
|
若用文本编辑器打开的证书是长这样的:
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 上做不断修整。
参考资料