iOS|iOS 使用OpenSSL 读取P12证书信息
1、OpenSSL 库使用pod 方式引入:
pod 'OpenSSL-Universal'
2、准备一个p12证书
示例:develop.p12, 密码: 123456
3、引入相关的头文件:
#import
#import
#import
#import
4、读取p12证书相关信息:
-(void)readP12Info {
NSString *filePath = [[NSBundle mainBundle]pathForResource:@"develop" ofType:@"p12"];
NSString *password = @"123456";
PKCS12 *p12 = NULL;
//p12对像:包含证书信息和秘钥
X509* usrCert = NULL;
//证书信息
EVP_PKEY* pkey = NULL;
//秘钥
STACK_OF(X509)* ca = NULL;
//证书信息栈
BIO*bio = NULL;
//BIO是封装了许多类型I/O接口细节的一种应用接口,可以和SSL连接、非加密的网络连接以及文件IO进行透明的连接。
//BIO更多信息:https://blog.csdn.net/liao20081228/article/details/77193729/OpenSSL_add_all_algorithms();
SSLeay_add_all_algorithms();
ERR_load_crypto_strings();
bio = BIO_new_file([filePath UTF8String], "r");
p12 = d2i_PKCS12_bio(bio, NULL);
//得到p12结构
PKCS12_parse(p12, [password UTF8String], &pkey, &usrCert, &ca);
//得到x509结构//序列号
NSString *serialNumber = [self __getSerialNumberString:usrCert];
//证书拥有者信息
NSString *userName = [self __getUserName:usrCert];
//颁发机构
NSString *issuserInfo = [self __getIssuserInfo:usrCert];
//生效时间
NSDate *beginDate = [self __getSignBeginDate:usrCert];
//过期时间
NSDate *expiryDate = [self __getExpiryDate:usrCert];
//SHA-1
NSString *sha1 = [self __sha1:usrCert];
//版本号
NSString *version = [self __getVersion:usrCert];
BIO_free_all(bio);
PKCS12_free(p12);
EVP_PKEY_free(pkey);
X509_free(usrCert);
}
//版本号
- (long)__getVersion:(X509 *)cert {
long version = X509_get_version(cert);
return version;
}
///序列号
- (NSString *)__getSerialNumberString:(X509*)usrCert {
ASN1_INTEGER *serial = X509_get_serialNumber(usrCert);
BIGNUM *bignum = ASN1_INTEGER_to_BN(serial, NULL);
char *res = BN_bn2hex(bignum);
NSString *serialStr = [NSString stringWithUTF8String:res];
return serialStr;
}///证书拥有者信息
- (NSString *)__getUserName:(X509 *)usrCert {
char szOutCN[256]={0};
X509_NAME *name = NULL;
name = usrCert->cert_info->subject;
X509_NAME_get_text_by_NID(name,NID_commonName,szOutCN,256);
NSString *nameStr = [NSString stringWithUTF8String:szOutCN];
return nameStr;
}///颁发机构
- (NSString *)__getIssuserInfo:(X509 *)usrCert {
X509_NAME_ENTRY *name_entry;
long Nid;
unsigned char msginfo[1024];
int msginfoLen;
NSMutableString *issuerInfo = [[NSMutableString alloc] init];
NSMutableString *certCN = [[NSMutableString alloc] init];
X509_NAME *issuer = X509_get_issuer_name(usrCert);
int entriesNum = sk_X509_NAME_ENTRY_num(issuer->entries);
for (int i = 0;
i < entriesNum;
i++) {
name_entry = sk_X509_NAME_ENTRY_value(issuer->entries, i);
Nid = OBJ_obj2nid(name_entry->object);
msginfoLen = name_entry->value->length;
memcpy(msginfo,name_entry->value->data,msginfoLen);
msginfo[msginfoLen]='\0';
switch(Nid) {
case NID_countryName://国家C
[issuerInfo appendString:[NSString stringWithFormat:@"C=%s,",msginfo]];
[certCN appendString:[NSString stringWithFormat:@"C=%s",msginfo]];
self.info.country = [NSString stringWithFormat:@"%s",msginfo];
break;
case NID_stateOrProvinceName://省ST
[issuerInfo appendString:[NSString stringWithFormat:@"ST=%s,",msginfo]];
self.info.province = [NSString stringWithFormat:@"%s",msginfo];
break;
case NID_localityName://地区L
[issuerInfo appendString:[NSString stringWithFormat:@"L=%s,",msginfo]];
self.info.region = [NSString stringWithFormat:@"%s",msginfo];
break;
case NID_organizationName://组织O=
[issuerInfo appendString:[NSString stringWithFormat:@"O=%s,",msginfo]];
self.info.organization = [NSString stringWithFormat:@"%s",msginfo];
break;
case NID_organizationalUnitName://单位OU
[issuerInfo appendString:[NSString stringWithFormat:@"OU=%s,",msginfo]];
self.info.unit = [NSString stringWithFormat:@"%s",msginfo];
break;
case NID_commonName://通用名CN
[issuerInfo appendString:[NSString stringWithFormat:@"CN=%s",msginfo]];
self.info.commonName = [NSString stringWithFormat:@"%s",msginfo];
break;
case NID_pkcs9_emailAddress://Mail
break;
}
}
return issuerInfo;
}///开始颁发的时间
- (NSDate *)__getSignBeginDate:(X509 *)cert {
ASN1_TIME *start = NULL;
time_t ttStart = {0};
// 颁发时间
start = X509_get_notBefore(cert);
ttStart = [self __skf_ext_ASN1_GetTimeT:start];
// 格林威治时间与北京时间相差八小时,所以加八小时。
ttStart = ttStart + 8 * 60 * 60;
NSDate *startDate = [NSDate dateWithTimeIntervalSince1970:ttStart];
return startDate;
}///有效时间
- (NSDate *)__getExpiryDate:(X509 *)cert {
ASN1_TIME *end = NULL;
time_t ttEnd = {0};
// 过期时间
end = X509_get_notAfter(cert);
ttEnd = [self __skf_ext_ASN1_GetTimeT:end];
ttEnd = ttEnd + 8 * 60 * 60;
NSDate *endDate = [NSDate dateWithTimeIntervalSince1970:ttEnd];
return endDate;
}///格林威治时间转本地时间
- (time_t)__skf_ext_ASN1_GetTimeT:(ASN1_TIME *)time {
struct tm t;
const char* str = (const char*) time->data;
size_t i = 0;
memset(&t, 0, sizeof(t));
if (time->type == V_ASN1_UTCTIME) {/* two digit year */
t.tm_year = (str[i++] - '0') * 10;
t.tm_year += (str[i++] - '0');
if (t.tm_year < 70)
t.tm_year += 100;
} else if (time->type == V_ASN1_GENERALIZEDTIME) {/* four digit year */
t.tm_year = (str[i++] - '0') * 1000;
t.tm_year+= (str[i++] - '0') * 100;
t.tm_year+= (str[i++] - '0') * 10;
t.tm_year+= (str[i++] - '0');
t.tm_year -= 1900;
}
t.tm_mon= (str[i++] - '0') * 10;
t.tm_mon += (str[i++] - '0') - 1;
// -1 since January is 0 not 1.
t.tm_mday = (str[i++] - '0') * 10;
t.tm_mday+= (str[i++] - '0');
t.tm_hour = (str[i++] - '0') * 10;
t.tm_hour+= (str[i++] - '0');
t.tm_min= (str[i++] - '0') * 10;
t.tm_min += (str[i++] - '0');
t.tm_sec= (str[i++] - '0') * 10;
t.tm_sec += (str[i++] - '0');
/* Note: we did not adjust the time based on time zone information */
return mktime(&t);
}
//指纹信息
- (NSString*) __sha1:(X509 *)cert {
PKCS12_SAFEBAG *safeBag = PKCS12_x5092certbag(cert);
NSData *certData = https://www.it610.com/article/[NSData dataWithBytes: safeBag->value.bag->value.x509cert->datalength:safeBag->value.bag->value.x509cert->length];
unsigned char sha1Buffer[CC_SHA1_DIGEST_LENGTH];
CC_SHA1(certData.bytes, (unsigned int)certData.length, sha1Buffer);
NSMutableString *fingerprint = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
for (int i = 0;
i < CC_SHA1_DIGEST_LENGTH;
++i){
[fingerprint appendFormat:@"%02x ",sha1Buffer[i]];
}
NSString *fingerString = [fingerprint stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
fingerString = [fingerString stringByReplacingOccurrencesOfString:@" " withString:@""];
PKCS12_SAFEBAG_free(safeBag);
return fingerString.uppercaseString;
}
备注:想要获取更多信息可以去X509对象中获取。
推荐阅读
- 由浅入深理解AOP
- 【译】20个更有效地使用谷歌搜索的技巧
- 2020-04-07vue中Axios的封装和API接口的管理
- mybatisplus如何在xml的连表查询中使用queryWrapper
- MybatisPlus|MybatisPlus LambdaQueryWrapper使用int默认值的坑及解决
- MybatisPlus使用queryWrapper如何实现复杂查询
- iOS中的Block
- Linux下面如何查看tomcat已经使用多少线程
- 使用composer自动加载类文件
- android|android studio中ndk的使用