gmssl编程之X509证书解析
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, ¬BeforeTLen);if (ret != SAR_Ok){LError("openSSLCert_get_notBefore failed.");return SAR_UnknownErr;}ret = openSSLCert_get_notAfter(pX509, notAfterT, ¬AfterTLen);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, >ype);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证书解析相关推荐
- Java并发编程之synchronized关键字解析
前言 公司加班太狠了,都没啥时间充电,这周终于结束了.这次整理了Java并发编程里面的synchronized关键字,又称为隐式锁,与JUC包中的Lock显示锁相对应:这个关键字从Java诞生开始就有 ...
- Java并发编程之ConcurrentHashMap原理解析
ConcurrentHashMap get: /*** 根据键值key获取value,根据key.equals方法判断两个元素是否相同* @param key 键* @return 如果key存在则返 ...
- Android 网络编程之OkHttp源码解析
前言:OkHttp框架是Android的网络请求框架,无数的项目都在使用着这个框架,重要性不言而喻; 本文会将OKHTTP的源码进行拆解,每个部分来单独学习,由简入深,循序渐进,篇幅较长,建议收藏,慢 ...
- openssl解析国密X509证书
openssl解析国密X509证书,把公钥拿出来重写一下就行了 x = strToX509(pbCert, pulCertLen); dwRet = getCertPubKey(x, ...
- 通过OpenSSL解析X509证书基本项
在之前的文章"通过OpenSSL解码X509证书文件"里,讲述了如何使用OpenSSL将证书文件解码,得到证书上下文结构体X509的方法.下面我们接着讲述如何通过证书上下文结构体X ...
- 【Qt】x509证书操作之解析证书信息
QSslCertificate支持x509证书信息的解析 证书信息接口 函数 功能 QByteArray version() const 版本 QByteArray serialNumber() co ...
- 异步编程之Promise(2):探究原理
异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...
- java解码p7b证书文件,通过OpenSSL解码X509证书文件
在Windows平台下,如果要解析一个X509证书文件,最直接的办法是使用微软的CryptoAPI.但是在非Windows平台下,就只能使用强大的开源跨平台库OpenSSL了.一个X509证书通过Op ...
- 基于python的modbus协议编程_通往未来的网络可编程之路:Netconf协议与YANG Model
近年来,随着全球云计算领域的不断发展与业务的不断增长,促使网络技术也不断发展,SDN技术应运而生,从最初的基于Openflow的转发与控制分离的核心思想,人们不断的去扩展SDN的外延,目前,人们可以达 ...
最新文章
- 没听说过这些,就不要说你懂并发了,three。
- 关于缓存命中率的几个关键问题!
- 网站优化中什么样的外链容易被删去?
- C#窗体控件更新(五)
- bzoj 4747: [Usaco2016 Dec]Counting Haybales
- 【对比分析六】JavaScript中GET和POST的区别及使用场景
- 设置某个元素的标签内容、设置元素的样式、层次选择器、总结选择器
- spark之4:编程指南
- 服务器复制不了文档,服务器复制粘贴不了
- 人群频率 | gnomAD数据库 (二) 后台数据的获取及质量评估
- 剑指offer面试题[9-2]-变态跳台阶
- 掘金小册大众评审团流程
- LaTeX快速入门(超详细~)
- 【经验】秀米排版指南|特殊布局(如文字环绕图片等无法使用秀米基本布局组合出来的布局)
- 手机html设计规范,手机网页设计尺寸规范具体是多少?
- UVA12235 - Help Bubu
- 电脑网线连接无线路由扩展设置
- 铜仁学院官网计算机二级报名,贵州铜仁学院2015年9月全国计算机等级考试报名通知...
- Android禁用系统更新
- 关于100M以太网的争用期问题
热门文章
- [4G/5G/6G专题基础-160]: 5G双链接与MCG/SCG/PCell/PSCell/SCell
- mysql opkg源_如何修改opkg源
- 什么是Mybatis?Mybatis有什么作用?
- 在篮球运动中,领先多少分才安全。体育作家Bill 开发了一个算法,用于判断篮球比赛中怎样的领先优势是不可超越的
- 为什么服务器选择Linux而不用Windows
- 【转】 测试职业思考:如何成为一名优秀的软件测试工程师
- Unity3D引擎之高级渲染技术
- html标签属性语音,HTML area 标签 media 属性
- 【无人机三维路径规划】基于蚁群算法实现无人机三维路径规划含Matlab代码
- ECCV 2022 | 网易互娱AI Lab提出首个基于单幅图片的实时高分辨率人脸重演算法