gmssl编程之X509证书解析

  • 引言
  • X509语法结构
  • 基本项
    • 证书版本号
    • 证书序列号
    • 证书颁发者
    • 证书使用者
    • 证书有效期
    • 证书公钥
  • 扩展项
    • 基本约束
    • 密钥用途
    • 增强型密钥用途
    • 颁发者标识
    • 使用者标识
    • CRL分发点
    • 颁发机构信息访问
  • 自定义私有扩展项

引言

最近空出了些时间整理了下以前的项目代码,看到了之前通过研究gmssl源码实现的一整套X509证书解析的代码,故记之以文。
(PS. 可能实现主要是为了满足项目需求,若有不对之处,还请指针ヾ( ̄▽ ̄))

下面小编列举了下X509证书结构的证书基本项(Basic Certificate Fields)、证书扩展项(Certificate Standard Extensions)以及自定义扩展项信息的解析。
若想了解更详细的X509结构,可查看RFC 5280规范。

X509语法结构

从RFC 5280规范中可看到X.509 v3证书语法结构如如下:

The X.509 v3 certificate basic syntax is as follows. For signature
calculation, the data that is to be signed is encoded using the ASN.1
distinguished encoding rules (DER) [X.690]. ASN.1 DER encoding is a
tag, length, value encoding system for each element.

Certificate  ::=  SEQUENCE  {tbsCertificate       TBSCertificate,signatureAlgorithm   AlgorithmIdentifier,signatureValue       BIT STRING  }TBSCertificate  ::=  SEQUENCE  {version         [0]  EXPLICIT Version DEFAULT v1,serialNumber         CertificateSerialNumber,signature            AlgorithmIdentifier,issuer               Name,validity             Validity,subject              Name,subjectPublicKeyInfo SubjectPublicKeyInfo,issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,-- If present, version MUST be v2 or v3subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,-- If present, version MUST be v2 or v3extensions      [3]  EXPLICIT Extensions OPTIONAL-- If present, version MUST be v3}Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }CertificateSerialNumber  ::=  INTEGERValidity ::= SEQUENCE {notBefore      Time,notAfter       Time }Time ::= CHOICE {utcTime        UTCTime,generalTime    GeneralizedTime }UniqueIdentifier  ::=  BIT STRINGSubjectPublicKeyInfo  ::=  SEQUENCE  {algorithm            AlgorithmIdentifier,subjectPublicKey     BIT STRING  }Extensions  ::=  SEQUENCE SIZE (1..MAX) OF ExtensionExtension  ::=  SEQUENCE  {extnID      OBJECT IDENTIFIER,critical    BOOLEAN DEFAULT FALSE,extnValue   OCTET STRING-- contains the DER encoding of an ASN.1 value-- corresponding to the extension type identified-- by extnID}

基本项

小编实现的证书基本项的解析包括:版本号、序列号、颁发者、使用者、有效期、公钥等。其它的信息项由于项目不需要所以就没实现了╰( ̄▽ ̄)╭。

证书版本号

/*获取x509证书中 版本号*/
int openSSLCert_get_version(X509 *pX509, unsigned char *pucVer, unsigned int *puiVerLen)
{if (!pX509 || !pucVer || !puiVerLen){LError("ERR_R_PASSED_NULL_PARAMETER.");return SAR_IndataErr;}if (*puiVerLen <= 2){LError("openSSLCert_get_version failed, SAF_R_BUFFER_TOO_SMALL.");return SAR_IndataLenErr;}int ver = X509_get_version(pX509);switch (ver){case 0:strcpy((char *)pucVer, "V1");break;case 1:strcpy((char *)pucVer, "V2");break;case 2:strcpy((char *)pucVer, "V3");break;default:LError("Unknown return value of X509_get_version.");return SAR_UnknownErr;}LDebug("version: {}", pucVer);return SAR_Ok;
}

证书序列号

/*获取证书序列号*/
int openSSLCert_get_SN(X509 *pX509, unsigned char *pucSN, unsigned int *puiSNLen)
{int ret = SAR_Ok;BIGNUM *bignum = NULL;char *serial = NULL;ASN1_INTEGER *asn1_i = NULL;if (!pX509 || !puiSNLen){LError("ERR_R_PASSED_NULL_PARAMETER.");return SAR_IndataErr;}asn1_i = X509_get_serialNumber(pX509);bignum = ASN1_INTEGER_to_BN(asn1_i, NULL);if (NULL == bignum){LError("openSSLCert_get_SN failed, ERR_R_ASN1_INTEGER_to_BN.");ret = SAR_UnknownErr;goto FREE_MEMORY;}
#if 0serial = BN_bn2hex(bignum);  //大数转16进制if (NULL == serial){LOG(ERROR) << "openSSLCert_get_SN, ERR_R_BN_bn2hex.";ret = SAR_UnknownErr;goto FREE_MEMORY;}
#elseserial = BN_bn2dec(bignum);  //大数转整数字符串if (NULL == serial){LError("openSSLCert_get_SN failed, ERR_R_BN_bn2dec.");ret = SAR_UnknownErr;goto FREE_MEMORY;}
#endifBN_free(bignum);if (!pucSN){*puiSNLen = strlen(serial) + 1;LError("pucSN is NULL.");ret = SAR_MemoryErr;goto FREE_MEMORY;}if (*puiSNLen < strlen(serial) + 1){LError("openSSLCert_get_SN failed, SAF_R_BUFFER_TOO_SMALL.");ret = SAR_BufferTooSmall;goto FREE_MEMORY;}strcpy_s((char *)pucSN, *puiSNLen, serial);*puiSNLen = strlen(serial);FREE_MEMORY:OPENSSL_free(serial);return ret;
}

证书颁发者

/*获取证书颁发者*/
int openSSL_get_Issuer(X509 *pX509, unsigned char *pucIssuer, unsigned int *puiIssuerLen)
{char tmp_buf[512] = { 0 };int tmpBufLen = sizeof(tmp_buf);X509_NAME *pCommonName = NULL;if (!pX509 || !puiIssuerLen){LError("ERR_R_PASSED_NULL_PARAMETER.");return SAR_IndataErr;}pCommonName = X509_get_issuer_name(pX509);if (!pCommonName){LError("X509_get_issuer_name failed.");return SAR_UnknownErr;}//获取issuer中所有信息,例如C=CN,DC=AIDDAID,DC=HSMz5k82u8NvyZ4uCoCLpBZqT8a2Vx2jW,OU=1234567890,CN=AIDIMCENTITYIDmemset(tmp_buf, '\0', sizeof(tmp_buf));X509_NAME_oneline(pCommonName, tmp_buf, tmpBufLen);for (int i = 1; i < (int)strlen(tmp_buf); i++){if (tmp_buf[i] == '/'){tmp_buf[i] = ',';}}tmpBufLen = strlen(tmp_buf);if (!pucIssuer){*puiIssuerLen = tmpBufLen + 1;LError("pucIssuer buffer is NULL.");return SAR_MemoryErr;}if (*puiIssuerLen < (unsigned int)tmpBufLen + 1){LError("pucIssuer buffer is too small.");return SAR_BufferTooSmall;}memcpy(pucIssuer, tmp_buf + 1, tmpBufLen);*puiIssuerLen = tmpBufLen;LDebug("issuer: {}", pucIssuer);return SAR_Ok;
}/*获取证书颁发者(issuer)中的某一项的值,例如C、O、OU、CN*/
int openSSLCert_get_Issuer_Entry(X509 *pX509, int nid, unsigned char *pucInfo, unsigned int *puiInfoLen)
{char tmp_buf[512] = { 0 };int tmpBufLen = sizeof(tmp_buf);X509_NAME *pCommonName = NULL;if (!pX509 || !puiInfoLen){LError("ERR_R_PASSED_NULL_PARAMETER.");return SAR_IndataErr;}pCommonName = X509_get_issuer_name(pX509);if (!pCommonName){LError("X509_get_issuer_name failed.");return SAR_UnknownErr;}switch (nid){//case NID_countryName:  //国家//case NID_stateOrProvinceName:  //省//case NID_localityName:  //地区case NID_organizationName:  //组织case NID_organizationalUnitName:  //单位case NID_commonName:  //通用名tmpBufLen = X509_NAME_get_text_by_NID(pCommonName, nid, tmp_buf, tmpBufLen);if (-1 == tmpBufLen){LError("X509_NAME_get_text_by_NID failed.");return SAR_UnknownErr;};break;default:LError("Invalid NID, not support yet.");return SAR_NotSupportYetErr;//break;}if (!pucInfo){*puiInfoLen = tmpBufLen + 1;LError("pucInfo buffer is NULL.");return SAR_MemoryErr;}if (*puiInfoLen < (ULONG)tmpBufLen + 1){LError("pucInfo buffer is too small.");return SAR_BufferTooSmall;}strcpy_s((char *)pucInfo, *puiInfoLen, tmp_buf);*puiInfoLen = tmpBufLen + 1;return SAR_Ok;
}

证书使用者

/*获取证书使用者*/
int openSSLCert_get_SubjectName(X509 *pX509, unsigned char *pucSubject, unsigned int *puiSubjectLen)
{char tmp_buf[512] = { 0 };int tmpBufLen = sizeof(tmp_buf);X509_NAME *pSubName = NULL;if (!pX509 || !puiSubjectLen){LError("ERR_R_PASSED_NULL_PARAMETER.");return SAR_IndataErr;}pSubName = X509_get_subject_name(pX509);if (!pSubName){LError("X509_get_subject_name failed.");return SAR_UnknownErr;}//获取subject中所有信息,例如C=CN,O=AIDDAID,OU=1234567890,CN=AIDIMCENTITYIDmemset(tmp_buf, '\0', sizeof(tmp_buf));X509_NAME_oneline(pSubName, tmp_buf, tmpBufLen);for (int i = 1; i < (int)strlen(tmp_buf); i++){if (tmp_buf[i] == '/'){tmp_buf[i] = ',';}}tmpBufLen = strlen(tmp_buf);if (!pucSubject){*puiSubjectLen = tmpBufLen + 1;LError("pucSubject buffer is NULL.");return SAR_MemoryErr;}if (*puiSubjectLen < (unsigned int)tmpBufLen + 1){LError("pucSubject buffer is too small.");return SAR_BufferTooSmall;}memcpy(pucSubject, tmp_buf + 1, tmpBufLen);*puiSubjectLen = tmpBufLen;LDebug("subject: {}", pucSubject);return SAR_Ok;
}/*获取证书使用者(Subject)中的某一项的值,例如C、O、OU、CN*/
int openSSLCert_get_SubjectName_Entry(X509 *pX509, int nid, unsigned char *pucInfo, unsigned int *puiInfoLen)
{char tmp_buf[512] = { '\0' };int tmpBufLen = sizeof(tmp_buf);X509_NAME *pSubName = NULL;if (!pX509 || !puiInfoLen){LError("ERR_R_PASSED_NULL_PARAMETER.");return SAR_IndataErr;}pSubName = X509_get_subject_name(pX509);if (!pSubName){LError("X509_get_subject_name failed.");return SAR_UnknownErr;}switch (nid){//case NID_countryName:  //国家//case NID_stateOrProvinceName:  //省//case NID_localityName:  //地区case NID_organizationName:  //组织case NID_organizationalUnitName:  //单位case NID_commonName:  //通用名case NID_pkcs9_emailAddress:  //邮箱地址tmpBufLen = X509_NAME_get_text_by_NID(pSubName, nid, tmp_buf, tmpBufLen);if (-1 == tmpBufLen){LError("X509_NAME_get_text_by_NID failed");return SAR_UnknownErr;};break;default:LError("Invalid NID, not support yet.");return SAR_NotSupportYetErr;break;}if (!pucInfo){*puiInfoLen = tmpBufLen + 1;LError("pucInfo buffer is NULL.");return SAR_MemoryErr;}if (*puiInfoLen < (ULONG)tmpBufLen + 1){LError("pucInfo buffer is too small.");return SAR_BufferTooSmall;}strcpy_s((char *)pucInfo, *puiInfoLen, tmp_buf);*puiInfoLen = tmpBufLen + 1;return SAR_Ok;
}

证书有效期

/*获取有效期开始时间, 时间字符串格式“YYYY-MM-DD HH:mm:ss” */
int openSSLCert_get_notBefore(X509 *pX509, unsigned char *pucInfo, unsigned int *puiInfoLen)
{ASN1_TIME *timeNotBefore = NULL;  //"YYMMDDhhmm[ss]Z"  返回的UTC格式的时间字符串time_t lResult = 0;int err = 0;char startTBuf[80] = { '\0' };struct tm* startTInfo;if (!pX509 || !puiInfoLen){LError("ERR_R_PASSED_NULL_PARAMETER.");return SAR_IndataErr;}//get notBefore from X509timeNotBefore = X509_get_notBefore(pX509);if (NULL == timeNotBefore){LError("X509_get_notBefore failure.");return SAR_IndataErr;}//ASN1_Time to time_tlResult = ASN1_TIME_get(timeNotBefore, &err);if (err != 0){LError("ASN1_Time convert to time_t failure.");return SAR_IndataErr;}//time_t format "YYYY-MM-DD HH:mm:ss"startTInfo = localtime(&lResult);strftime(startTBuf, 80, "%Y-%m-%d %H:%M:%S", startTInfo);if (!pucInfo){*puiInfoLen = strlen(startTBuf) + 1;LError("pucInfo buffer is NULL.");return SAR_MemoryErr;}if (*puiInfoLen < strlen(startTBuf) + 1){LError("pucInfo buffer is too small, needed:{}", strlen(startTBuf) + 1);return SAR_BufferTooSmall;}memset(pucInfo, '\0', *puiInfoLen);memcpy(pucInfo, startTBuf, strlen(startTBuf));*puiInfoLen = strlen(startTBuf);//LOG(DEBUG) << "notBefore:" << pucInfo;return SAR_Ok;
}/*获取有效期截止时间,时间字符串格式“YYYY-MM-DD HH:mm:ss”*/
int openSSLCert_get_notAfter(X509 *pX509, unsigned char *pucInfo, unsigned int *puiInfoLen)
{ASN1_TIME *timeNotAfter = NULL;   //"YYMMDDhhmm[ss]Z"  返回的UTC格式的时间字符串time_t lResult = 0;int err = 0;char endTBuf[80] = { '\0' };struct tm* endTInfo;if (!pX509 || !puiInfoLen){LError("ERR_R_PASSED_NULL_PARAMETER.");return SAR_IndataErr;}timeNotAfter = X509_get_notAfter(pX509);if (NULL == timeNotAfter){LError("X509_get_notAfter failure.");return SAR_UnknownErr;}//ASN1_Time to time_tlResult = ASN1_TIME_get(timeNotAfter, &err);if (err != 0){LError("ASN1_Time convert to time_t failure.");return SAR_IndataErr;}//time_t format "YYYY-MM-DD HH:mm:ss"endTInfo = localtime(&lResult);strftime(endTBuf, 80, "%Y-%m-%d %H:%M:%S", endTInfo);if (!pucInfo){*puiInfoLen = strlen(endTBuf) + 1;LError("pucInfo buffer is NULL.");return SAR_MemoryErr;}if (*puiInfoLen < strlen(endTBuf) + 1){LError("pucInfo buffer is too small, needed: {}", strlen(endTBuf) + 1);return SAR_BufferTooSmall;}memset(pucInfo, '\0', *puiInfoLen);memcpy(pucInfo, endTBuf, strlen(endTBuf));*puiInfoLen = strlen(endTBuf);//LOG(DEBUG) << "notAfter:" << pucInfo;return SAR_Ok;
}/*获取有效期, 格式为开始时间+截止时间,中间以“,”分隔, (例如“2019-10-26 09:34:40,2020-10-26 09:34:40”)*/
int openSSLCert_get_validTime(X509 *pX509, unsigned char *pucInfo, unsigned int *puiInfoLen)
{unsigned char notBeforeT[24] = { '\0' };unsigned int notBeforeTLen = 24;unsigned char notAfterT[24] = { '\0' };unsigned int notAfterTLen = 24;int ret = SAR_UnknownErr;if (!pX509 || !puiInfoLen){LError("ERR_R_PASSED_NULL_PARAMETER.");return SAR_IndataErr;}ret = openSSLCert_get_notBefore(pX509, notBeforeT, &notBeforeTLen);if (ret != SAR_Ok){LError("openSSLCert_get_notBefore failed.");return SAR_UnknownErr;}ret = openSSLCert_get_notAfter(pX509, notAfterT, &notAfterTLen);if (ret != SAR_Ok){LError("openSSLCert_get_notAfter failed.");return SAR_UnknownErr;}if (!pucInfo){*puiInfoLen = notBeforeTLen + notAfterTLen + 2;LError("pucInfo buffer is NULL.");return SAR_MemoryErr;}if (*puiInfoLen < notBeforeTLen + notAfterTLen + 2){LError("pucInfo buffer is too small.");return SAR_BufferTooSmall;}memset(pucInfo, 0x00, *puiInfoLen);strcpy((char *)pucInfo, (const char *)notBeforeT);strcat((char *)pucInfo, ",");strncat((char *)pucInfo, (const char *)notAfterT, notAfterTLen);*puiInfoLen = notBeforeTLen + notAfterTLen + 1;return SAR_Ok;
}

证书公钥

/*获取证书公钥*/
int openSSLCert_get_PubKey(X509 *pX509, unsigned char *pucInfo, unsigned int *puiInfoLen)
{if (!pX509 || !puiInfoLen){LError("ERR_R_PASSED_NULL_PARAMETER.");return SAR_IndataErr;}
#if 0// 以下虽为正规方式 (个人认为)// 注,若生成的证书x509结构中cert_info->X509_pubkey->EVP_PKEY 未填入值。故用X509_get_pubkey取不到数据EVP_PKEY *pubKey = NULL;unsigned char *pTmp = NULL;int pubLen = 0;pubKey = X509_get_pubkey(pX509);if (!pubKey){LError("X509_get_pubkey failed");return SAR_UnknownErr;}pubLen = i2d_PublicKey(pubKey, NULL);if (!pucInfo){*puiInfoLen = pubLen;LError("pucInfo buffer is NULL.");return SAR_MemoryErr;}if (*puiInfoLen < pubLen){LError("pucInfo buffer is too small.");return SAR_BufferTooSmall;}pTmp = pucInfo;//把证书公钥转为DER编码的数据*puiInfoLen = i2d_PublicKey(pubKey, &pTmp);
#else//通过X509_get0_pubkey_bitstr获取X509_pubkey_st结构中public_key成员的数据ASN1_BIT_STRING * pubkey;pubkey = X509_get0_pubkey_bitstr(pX509);int nlen = pubkey->length;//LOG(DEBUG) << std::hex << std::setw(2) << pubkey->data << std::endl;if (!pucInfo){*puiInfoLen = nlen;LError("pucInfo buffer is NULL.");return SAR_MemoryErr;}if (*puiInfoLen < (unsigned int)nlen){LError("pucInfo buffer is too small.");return SAR_BufferTooSmall;}memset(pucInfo, '\0', *puiInfoLen);memcpy(pucInfo, pubkey->data, nlen);*puiInfoLen = nlen;#endifreturn SAR_Ok;
}

扩展项

通用根据项目需要,小编实现的扩展信息项的解析包括:基本约束、密钥用途、增强型密钥用途、颁发者标识、使用者标识、CRL分发点、颁发机构信息访问等。

基本约束

/*获取证书扩展属性:基本约束*/
int openSSLCert_get_ext_BasicConstraints(X509 *pX509, unsigned char *pucInfo, unsigned int *puiInfoLen)
{int crit = 0;char value[512] = { 0 };BASIC_CONSTRAINTS *bcons = NULL;if (!pX509 || !puiInfoLen){LError("ERR_R_PASSED_NULL_PARAMETER.");return SAR_IndataErr;}bcons = (BASIC_CONSTRAINTS*)X509_get_ext_d2i(pX509, NID_basic_constraints, &crit, NULL);if (!bcons){LError("X509_get_ext_d2i failure, attr(NID_basic_constraints) not exist");return SAR_UnknownErr;}if (!bcons->ca){strcat_s(value, sizeof(value), "Subject Type=End Entity; ");strcat_s(value, sizeof(value), "Path Length Constraint=None");}else{char temp[128] = { 0 };sprintf_s(temp, sizeof(temp), "Path Length Constraint=%d", bcons->pathlen);strcat_s(value, sizeof(value), "Subject Type=CA; ");strcat_s(value, sizeof(value), temp);}BASIC_CONSTRAINTS_free(bcons);if (!pucInfo){*puiInfoLen = strlen(value) + 1;LError("pucInfo buffer is NULL.");return SAR_MemoryErr;}if (*puiInfoLen < (strlen(value) + 1)){LError("pucInfo buffer is too small.");return SAR_BufferTooSmall;}strcpy_s((char *)pucInfo, *puiInfoLen, value);*puiInfoLen = strlen(value) + 1;LDebug("ExtBasicConstraints: {}", pucInfo);return SAR_Ok;
}

密钥用途

/*获取证书扩展属性:密钥用途*/
int openSSLCert_get_ext_keyUsage(X509 *pX509, unsigned char *pucInfo, unsigned int *puiInfoLen)
{//密钥用法ASN1_BIT_STRING *lASN1UsageStr = NULL;unsigned short usage = 0;char temp[32] = { 0 };char value[512] = { 0 };if (!pX509 || !puiInfoLen){LError("ERR_R_PASSED_NULL_PARAMETER.");return SAR_IndataErr;}int crit = 0;lASN1UsageStr = (ASN1_BIT_STRING *)X509_get_ext_d2i(pX509, NID_key_usage, &crit, NULL);if (!lASN1UsageStr){LError("X509_get_ext_d2i failure, attr(NID_key_usage) not exist");return SAR_UnknownErr;}if (crit){strcat_s(value, sizeof(value), "critical, ");}usage = lASN1UsageStr->data[0];if (lASN1UsageStr->length > 1){usage |= lASN1UsageStr->data[1] << 8;}sprintf_s(temp, sizeof(temp), "(%x)", usage);if (usage & KU_DIGITAL_SIGNATURE){strcat_s(value, sizeof(value), "Digital Signature, ");}if (usage & KU_NON_REPUDIATION){strcat_s(value, sizeof(value), "Non-Repudiation, ");}if (usage & KU_KEY_ENCIPHERMENT){strcat_s(value, sizeof(value), "Key Encipherment, ");}if (usage & KU_DATA_ENCIPHERMENT){strcat_s(value, sizeof(value), "Data  Encipherment, ");}if (usage & KU_KEY_AGREEMENT){strcat_s(value, sizeof(value), "Key  Agreement, ");}if (usage & KU_KEY_CERT_SIGN){strcat_s(value, sizeof(value), "Certificate Signature, ");}if (usage & KU_CRL_SIGN){strcat_s(value, sizeof(value), "CRL Signature, ");}strcat_s(value, sizeof(value), temp);ASN1_BIT_STRING_free(lASN1UsageStr);if (!pucInfo){*puiInfoLen = strlen(value) + 1;LError("pucInfo buffer is NULL.");return SAR_MemoryErr;}if (*puiInfoLen < (strlen(value) + 1)){LError("pucInfo buffer is too small.");return SAR_BufferTooSmall;}strcpy_s((char *)pucInfo, *puiInfoLen, value);*puiInfoLen = strlen(value) + 1;LDebug("KeyUsage: {}", pucInfo);return SAR_Ok;
}

增强型密钥用途

/*获取证书扩展属性:增强型密钥用途*/
int openSSLCert_get_ext_EnhancedKeyUsage(X509 *pX509, unsigned char *pucInfo, unsigned int *puiInfoLen)
{int i = 0;char value[512] = { 0 };EXTENDED_KEY_USAGE* extusage;if (!pX509 || !puiInfoLen){LError("ERR_R_PASSED_NULL_PARAMETER.");return -1;}int crit = 0;extusage = (EXTENDED_KEY_USAGE *)X509_get_ext_d2i(pX509, NID_ext_key_usage, &crit, NULL);if (!extusage){LError("X509_get_ext_d2i failure, attr(NID_ext_key_usage) not exist");return -1;}//是否为关键扩展项if (crit){strcat_s(value, sizeof(value), "critical, ");}for (i = 0; i < sk_ASN1_OBJECT_num(extusage); i++){switch (OBJ_obj2nid(sk_ASN1_OBJECT_value(extusage, i))) {case NID_server_auth:strcat_s(value, sizeof(value), "serverAuth, ");break;case NID_client_auth:strcat_s(value, sizeof(value), "clientAuth, ");break;case NID_email_protect:strcat_s(value, sizeof(value), "emailProtection, ");break;case NID_code_sign:strcat_s(value, sizeof(value), "codeSigning, ");break;case NID_OCSP_sign:strcat_s(value, sizeof(value), "OCSPSigning, ");break;case NID_time_stamp:strcat_s(value, sizeof(value), "timeStamping, ");break;case NID_ms_code_ind:strcat_s(value, sizeof(value), "msCodeInd, ");break;case NID_ms_code_com:strcat_s(value, sizeof(value), "msCodeCom, ");break;case NID_ms_ctl_sign:strcat_s(value, sizeof(value), "msCTLSign, ");break;case NID_ms_efs:strcat_s(value, sizeof(value), "msEFS, ");break;case NID_ns_sgc:strcat_s(value, sizeof(value), "nsSGC, ");break;case NID_ms_sgc:strcat_s(value, sizeof(value), "msSGC, ");break;case NID_dvcs:strcat_s(value, sizeof(value), "DVCS, ");break;case NID_anyExtendedKeyUsage:strcat_s(value, sizeof(value), "anyExtendedKeyUsage, ");break;}}sk_ASN1_OBJECT_pop_free(extusage, ASN1_OBJECT_free);int len = strlen(value);if (len > 2){value[len - 1] = 0; //去除末尾逗号value[len - 2] = 0;}if (!pucInfo){*puiInfoLen = strlen(value) + 1;LError("pucInfo buffer is NULL.");return -1;}if (*puiInfoLen < (strlen(value) + 1)){LError("pucInfo buffer is too small.");return -1;}strcpy_s((char *)pucInfo, *puiInfoLen, value);*puiInfoLen = strlen(value) + 1;LDebug("EnhancedKeyUsage: {}", (char *)pucInfo);return 0;
}

颁发者标识

/*获取证书扩展属性:颁发者标识*/
int openSSLCert_get_ext_AuthorityIdentifier(X509 *pX509, unsigned char *pucInfo, unsigned int *puiInfoLen)
{int i = 0;int crit = 0;char value[512] = { 0 };AUTHORITY_KEYID *akeyid = NULL;if (!pX509 || !puiInfoLen){LError("ERR_R_PASSED_NULL_PARAMETER.");return SAR_IndataErr;}akeyid = (AUTHORITY_KEYID*)X509_get_ext_d2i(pX509, NID_authority_key_identifier, &crit, NULL);if (!akeyid){LError("X509_get_ext_d2i failure, attr(NID_authority_key_identifier) not exist");return SAR_UnknownErr;}strcat_s(value, sizeof(value), "KeyID=");for (i = 0; i < akeyid->keyid->length; i++){char keyid[8] = { 0 };sprintf_s(keyid, 8, "%x ", akeyid->keyid->data[i]);strcat_s(value, sizeof(value), keyid);}AUTHORITY_KEYID_free(akeyid);if (!pucInfo){*puiInfoLen = strlen(value) + 1;LError("pucInfo buffer is NULL.");return SAR_MemoryErr;}if (*puiInfoLen < (strlen(value) + 1)){LError("pucInfo buffer is too small.");return SAR_BufferTooSmall;}strcpy_s((char *)pucInfo, *puiInfoLen, value);*puiInfoLen = strlen(value) + 1;return SAR_Ok;
}

使用者标识

/*获取证书扩展属性:使用者标识*/
int openSSLCert_get_ext_SubjectIdentifier(X509 *pX509, unsigned char *pucInfo, unsigned int *puiInfoLen)
{int i = 0;int crit = 0;char value[512] = { 0 };ASN1_OCTET_STRING *skid = NULL;if (!pX509 || !puiInfoLen){LError("ERR_R_PASSED_NULL_PARAMETER.");return SAR_IndataErr;}skid = (ASN1_OCTET_STRING*)X509_get_ext_d2i(pX509, NID_subject_key_identifier, &crit, NULL);if (!skid){LError("X509_get_ext_d2i failure, attr(NID_subject_key_identifier) not exist");return SAR_UnknownErr;}for (i = 0; i < skid->length; i++){char keyid[8] = { 0 };sprintf_s(keyid, 8, "%x ", skid->data[i]);strcat_s(value, sizeof(value), keyid);}ASN1_OCTET_STRING_free(skid);if (!pucInfo){*puiInfoLen = strlen(value) + 1;LError("pucInfo buffer is NULL.");return SAR_MemoryErr;}if (*puiInfoLen < (strlen(value) + 1)){LError("pucInfo buffer is too small.");return SAR_BufferTooSmall;}strcpy_s((char *)pucInfo, *puiInfoLen, value);*puiInfoLen = strlen(value) + 1;return SAR_Ok;
}

CRL分发点

/*获取证书扩展属性:CRL分发点*/
int openSSLCert_get_ext_CRLDistPoints(X509 *pX509, unsigned char *pucInfo, unsigned int *puiInfoLen)
{int i = 0;int crit = 0;char value[512] = { 0 };CRL_DIST_POINTS *crlpoints = NULL;if (!pX509 || !puiInfoLen){LError("ERR_R_PASSED_NULL_PARAMETER.");return SAR_IndataErr;}crlpoints = (CRL_DIST_POINTS*)X509_get_ext_d2i(pX509, NID_crl_distribution_points, &crit, NULL);if (!crlpoints){LError("X509_get_ext_d2i failure, attr(NID_crl_distribution_points) not exist");return SAR_UnknownErr;}for (i = 0; i < sk_DIST_POINT_num(crlpoints); i++){int j, gtype;GENERAL_NAMES *gens;GENERAL_NAME *gen;ASN1_STRING *uri;DIST_POINT *dp = sk_DIST_POINT_value(crlpoints, i);if (!dp->distpoint || dp->distpoint->type != 0)continue;gens = dp->distpoint->name.fullname;for (j = 0; j < sk_GENERAL_NAME_num(gens); j++){gen = sk_GENERAL_NAME_value(gens, j);uri = (ASN1_STRING*)GENERAL_NAME_get0_value(gen, &gtype);if (gtype == GEN_URI && ASN1_STRING_length(uri) > 6){char *uptr = (char *)ASN1_STRING_data(uri);if (strlen(value) > 0){strcat_s(value, 512, " | ");}strcat_s(value, 512, uptr);}}}CRL_DIST_POINTS_free(crlpoints);if (!pucInfo){*puiInfoLen = strlen(value) + 1;LError("pucInfo buffer is NULL.");return SAR_MemoryErr;}if (*puiInfoLen < (strlen(value) + 1)){LError("pucInfo buffer is too small.");return SAR_BufferTooSmall;}strcpy_s((char *)pucInfo, *puiInfoLen, value);*puiInfoLen = strlen(value) + 1;return SAR_Ok;
}

颁发机构信息访问

/*获取证书扩展属性:颁发机构信息访问*/
int openSSLCert_get_ext_AuthorityInfoAccess(X509 *pX509, unsigned char *pucInfo, unsigned int *puiInfoLen)
{int i = 0;int crit = 0;char value[512] = { 0 };AUTHORITY_INFO_ACCESS *accinfo = NULL;if (!pX509 || !puiInfoLen){LError("ERR_R_PASSED_NULL_PARAMETER.");return SAR_IndataErr;}accinfo = (AUTHORITY_INFO_ACCESS*)X509_get_ext_d2i(pX509, NID_info_access, &crit, NULL);if (!accinfo){LError("X509_get_ext_d2i failure, attr(NID_info_access) not exist");return SAR_UnknownErr;}for (i = 0; i < sk_ACCESS_DESCRIPTION_num(accinfo); i++){ACCESS_DESCRIPTION *ad = sk_ACCESS_DESCRIPTION_value(accinfo, i);if (ad && ad->location && ad->location->type == GEN_URI){char temp[256] = { 0 };char method[32] = { 0 };char *uptr = (char *)ASN1_STRING_data(ad->location->d.uniformResourceIdentifier);if (strlen(value) > 0){strcat_s(value, 512, " | ");}OBJ_obj2txt(method, 32, ad->method, 1);sprintf_s(temp, 256, "Access Method=证书颁发机构颁发者 (%s), \r\n", method);strcat_s(value, 512, temp);strcat_s(value, 512, uptr);}}AUTHORITY_INFO_ACCESS_free(accinfo);if (!pucInfo){*puiInfoLen = strlen(value) + 1;LError("pucInfo buffer is NULL.");return SAR_MemoryErr;}if (*puiInfoLen < (strlen(value) + 1)){LError("pucInfo buffer is too small.");return SAR_BufferTooSmall;}strcpy_s((char *)pucInfo, *puiInfoLen, value);*puiInfoLen = strlen(value) + 1;return SAR_Ok;
}

自定义私有扩展项

私有自定义扩展项时通过自定义的OID值来进行查找并解析。

/*获取证书中自定义私有扩展项信息*/
int openSSLCert_get_ext_SelfDefinedExtension(X509 *pX509, const char *pcPriOid, unsigned char *pucInfo, unsigned int *puiInfoLen)
{if (!pX509 || !pcPriOid || !puiInfoLen){LError("ERR_R_PASSED_NULL_PARAMETER.");return SAR_IndataErr;}ASN1_OBJECT *obj;obj = OBJ_txt2obj(pcPriOid, 1);if (obj == NULL){return SAR_NotExportErr;  //未找到指定的自定义扩展项}int idx = X509_get_ext_by_OBJ(pX509, obj, -1);/* Does extension exist? */if (idx == -1) {return SAR_NotExportErr;  //未找到指定的自定义扩展项}X509_EXTENSION *extension = X509_get_ext(pX509, idx);if (NULL == extension){LError("X509_get_ext fail");return SAR_IndataErr;}ASN1_OCTET_STRING *ext_val = X509_EXTENSION_get_data(extension);if (!ext_val){LError("X509_EXTENSION_get_data return null");return SAR_IndataErr;}if (!pucInfo){*puiInfoLen = ext_val->length + 1;LError("pucInfo buffer is NULL.");return SAR_MemoryErr;}if (*puiInfoLen < (ext_val->length + 1)){LError("pucInfo buffer is too small.");return SAR_BufferTooSmall;}memset(pucInfo, '\0', *puiInfoLen);memcpy(pucInfo, ext_val->data, ext_val->length);*puiInfoLen = ext_val->length;return SAR_Ok;
}

我不休息我还能学 ⊂(‘ω’⊂ )))Σ≡=─༄༅༄༅༄༅༄༅༄༅

gmssl编程之X509证书解析相关推荐

  1. Java并发编程之synchronized关键字解析

    前言 公司加班太狠了,都没啥时间充电,这周终于结束了.这次整理了Java并发编程里面的synchronized关键字,又称为隐式锁,与JUC包中的Lock显示锁相对应:这个关键字从Java诞生开始就有 ...

  2. Java并发编程之ConcurrentHashMap原理解析

    ConcurrentHashMap get: /*** 根据键值key获取value,根据key.equals方法判断两个元素是否相同* @param key 键* @return 如果key存在则返 ...

  3. Android 网络编程之OkHttp源码解析

    前言:OkHttp框架是Android的网络请求框架,无数的项目都在使用着这个框架,重要性不言而喻; 本文会将OKHTTP的源码进行拆解,每个部分来单独学习,由简入深,循序渐进,篇幅较长,建议收藏,慢 ...

  4. openssl解析国密X509证书

    openssl解析国密X509证书,把公钥拿出来重写一下就行了         x = strToX509(pbCert, pulCertLen); dwRet = getCertPubKey(x,  ...

  5. 通过OpenSSL解析X509证书基本项

    在之前的文章"通过OpenSSL解码X509证书文件"里,讲述了如何使用OpenSSL将证书文件解码,得到证书上下文结构体X509的方法.下面我们接着讲述如何通过证书上下文结构体X ...

  6. 【Qt】x509证书操作之解析证书信息

    QSslCertificate支持x509证书信息的解析 证书信息接口 函数 功能 QByteArray version() const 版本 QByteArray serialNumber() co ...

  7. 异步编程之Promise(2):探究原理

    异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...

  8. java解码p7b证书文件,通过OpenSSL解码X509证书文件

    在Windows平台下,如果要解析一个X509证书文件,最直接的办法是使用微软的CryptoAPI.但是在非Windows平台下,就只能使用强大的开源跨平台库OpenSSL了.一个X509证书通过Op ...

  9. 基于python的modbus协议编程_通往未来的网络可编程之路:Netconf协议与YANG Model

    近年来,随着全球云计算领域的不断发展与业务的不断增长,促使网络技术也不断发展,SDN技术应运而生,从最初的基于Openflow的转发与控制分离的核心思想,人们不断的去扩展SDN的外延,目前,人们可以达 ...

最新文章

  1. 没听说过这些,就不要说你懂并发了,three。
  2. 关于缓存命中率的几个关键问题!
  3. 网站优化中什么样的外链容易被删去?
  4. C#窗体控件更新(五)
  5. bzoj 4747: [Usaco2016 Dec]Counting Haybales
  6. 【对比分析六】JavaScript中GET和POST的区别及使用场景
  7. 设置某个元素的标签内容、设置元素的样式、层次选择器、总结选择器
  8. spark之4:编程指南
  9. 服务器复制不了文档,服务器复制粘贴不了
  10. 人群频率 | gnomAD数据库 (二) 后台数据的获取及质量评估
  11. 剑指offer面试题[9-2]-变态跳台阶
  12. 掘金小册大众评审团流程
  13. LaTeX快速入门(超详细~)
  14. 【经验】秀米排版指南|特殊布局(如文字环绕图片等无法使用秀米基本布局组合出来的布局)
  15. 手机html设计规范,手机网页设计尺寸规范具体是多少?
  16. UVA12235 - Help Bubu
  17. 电脑网线连接无线路由扩展设置
  18. 铜仁学院官网计算机二级报名,贵州铜仁学院2015年9月全国计算机等级考试报名通知...
  19. Android禁用系统更新
  20. 关于100M以太网的争用期问题

热门文章

  1. [4G/5G/6G专题基础-160]: 5G双链接与MCG/SCG/PCell/PSCell/SCell
  2. mysql opkg源_如何修改opkg源
  3. 什么是Mybatis?Mybatis有什么作用?
  4. 在篮球运动中,领先多少分才安全。体育作家Bill 开发了一个算法,用于判断篮球比赛中怎样的领先优势是不可超越的
  5. 为什么服务器选择Linux而不用Windows
  6. 【转】 测试职业思考:如何成为一名优秀的软件测试工程师
  7. Unity3D引擎之高级渲染技术
  8. html标签属性语音,HTML area 标签 media 属性
  9. 【无人机三维路径规划】基于蚁群算法实现无人机三维路径规划含Matlab代码
  10. ECCV 2022 | 网易互娱AI Lab提出首个基于单幅图片的实时高分辨率人脸重演算法