举个🌰,比如说我们希望通过 App 获取存储在沙盒下的证书过期时间
获取本地证书
非 P12 证书获取
1.通过本地路径获取证书数据 Data
2.通过证书 Data 获取 CertificateRef
NSData *certData = [NSData dataWithContentsOfFile:path];
// if (certData.length == 0) return ;
SecCertificateRef certRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certData);
// if (!certRef) return ;
CFRelease(certRef);
P12 证书获取方式
- 通过路径获取证书数据 Data
- 通过 Import PCK 方法获取证书数组 CertIdentifyTrustDictArrays
- 通过证书的 Identify 创建 CertificateRef
CFDictionaryRef secImportOptions = (__bridge CFDictionaryRef) @{(__bridge id) kSecImportExportPassphrase : psk};
CFArrayRef secImportItems = NULL; // 证书列表
NSData *pk12Data = [NSData dataWithContentsOfFile:path];
OSStatus status = SecPKCS12Import((__bridge CFDataRef) pk12Data, (CFDictionaryRef) secImportOptions, &secImportItems);
if (status == errSecSuccess
&& secImportItems && CFArrayGetCount(secImportItems) > 0) {
// Identify
CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex(secImportItems,0);
const void*tempIdentity = NULL;
tempIdentity = CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemIdentity);
SecIdentityRef identify = (SecIdentityRef)tempIdentity;
SecCertificateRef certRef;
OSStatus status = SecIdentityCopyCertificate(identify, &certRef);
if (status == errSecSuccess) {
SecCertificateRef certRef = SecCertificateCopyData(certRef);
CFRelease(certRef);
}
}
通过 SecCertificateRef 获取证书信息
目前暂未找到 Security Framework 有相关 Api
所以使用了开源库 Openssl-iOS GitHub
Openssl-iOS 的使用
下载完成后,打开项目根目录,推荐使用 Go2shell 工具,可以直接打开终端并进入当前目录路径下
运行 shell 脚本 ./build-libssl.sh
进行编译输出
最后在 lib 下找到 libssl.a、libcrypto.a 拉到项目中的 Framework
然后将 include 文件夹拉到项目文件夹中,但是可以不用拉到 .xcodeproj / .xcworkspace 中
最后一步,在 Target 中的 BuildSetting 搜索🔍 Header Search Paths 然后将 include 文件路径拖进去
这样就可以使用 Openssl-iOS
修改支持的指令集 [Optional]
我下载的那个版本中,build-libssl.sh 中定义了 Target 编译的指令集
DEFAULTTARGETS 字段中只支持 ios64-cross-arm64 ios64-cross-arm64e
后面导致我使用该库的项目中打包出现了报错,但是我使用真机编译运行的时候没有问题
原因就是因为我的项目中默认支持 armv7s,armv7,而在 Openssl-iOS 编译的时候静态库没有带这两个
该设置项在 TARGET -> Build Settings -> Architectures -> Valid Architectures 中
修改 build-libssl.h 中的 DEFAULTTARGETS
DEFAULTTARGETS="ios-cross-armv7s ios-cross-armv7 ios-sim-cross-x86_64 ios64-cross-arm64 ios64-cross-arm64e tvos-sim-cross-x86_64 tvos64-cross-arm64"
自己可根据需要进行增删
armv7 和 armv7s 是属于 32位 CPU, iOS 系统版本中,32 位仅支持到 iOS 10,所以如果使用 armv7 和 armv7s,需要同时修改 IOS_MIN_SDK_VERSION
IOS_MIN_SDK_VERSION="10.0" // 10.0 以下都可以
编译过程中可能会报错,Openssl-iOS 会输出对应 .log 日志,可以根据对应问题进行修改
通过 Openssl-iOS 获取证书时间
通过上面获取到的 SecCertificateRef 初始化 NSData,然后进行获取证书信息
初始化成 X509 还可以获取其他证书信息
NSData *data = CFBridgingRelease(SecCertificateCopyData(certRef));
const unsigned char *certificateDataBytes = [data bytes];
X509 *certificateX509 = d2i_X509(NULL, &certificateDataBytes, [data length]);
ASN1_TIME *not_before = X509_getm_notBefore(certificateX509);
ASN1_TIME *not_after = X509_getm_notAfter(certificateX509);
/// 证书过期时间
char not_after_str[DATE_LEN];
convert_ASN1TIME(not_after, not_after_str, DATE_LEN);
/// 证书创建时间
char not_before_str[DATE_LEN];
convert_ASN1TIME(not_before, not_before_str, DATE_LEN);
// 将时间转换为时间戳
NSMutableString *beforeString = [[NSMutableString alloc]initWithFormat:@"%s", not_before_str];
NSMutableString *afterString = [[NSMutableString alloc]initWithFormat:@"%s", not_after_str];
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
[formatter setDateFormat:@"MM dd hh:mm:ss yyyy zzz"];
NSDate *afterDate = [formatter dateFromString:afterString];
NSTimeInterval afterTimeStamp = afterDate.timeIntervalSince1970;
convert_ASN1TIME 用于将 ASN1_Time 转换为 char[]
int convert_ASN1TIME(ASN1_TIME *t, char* buf, size_t len)
{
int rc;
BIO *b = BIO_new(BIO_s_mem());
rc = ASN1_TIME_print(b, t);
if (rc <= 0) {
BIO_free(b);
return EXIT_FAILURE;
}
rc = BIO_gets(b, buf, len);
if (rc <= 0) {
BIO_free(b);
return EXIT_FAILURE;
}
BIO_free(b);
return EXIT_SUCCESS;
}
网友评论