iOS 使用OpenSSL 讀取P12證書信息

1、OpenSSL 庫使用pod 方式引入:

pod 'OpenSSL-Universal'

2、準(zhǔn)備一個p12證書

示例:develop.p12, 密碼: 123456

3、引入相關(guān)的頭文件:

#import <openssl/pkcs12.h>
#import <openssl/err.h>
#import <openssl/pem.h>
#import <CommonCrypto/CommonDigest.h>

4、讀取p12證書相關(guān)信息:

-  (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接口細節(jié)的一種應(yīng)用接口,可以和SSL連接、非加密的網(wǎng)絡(luò)連接以及文件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結(jié)構(gòu)
      PKCS12_parse(p12, [password UTF8String], &pkey, &usrCert, &ca); //得到x509結(jié)構(gòu)

      //序列號
      NSString *serialNumber = [self __getSerialNumberString:usrCert];
      //證書擁有者信息
      NSString *userName = [self __getUserName:usrCert];
      //頒發(fā)機構(gòu)
      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;
}

///頒發(fā)機構(gòu)
- (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://地區(qū)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;
}

///開始頒發(fā)的時間
- (NSDate *)__getSignBeginDate:(X509 *)cert {
    ASN1_TIME *start = NULL;
    time_t ttStart = {0};
    // 頒發(fā)時間
    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;
}

///格林威治時間轉(zhuǎn)本地時間
- (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 = [NSData dataWithBytes: safeBag->value.bag->value.x509cert->data   length: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對象中獲取。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容