gmssl编程之X509证书解析

引言

最近空出了些时间整理了下以前的项目代码,看到了之前通过研究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 v3
                             subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
                             -- If present, version MUST be v2 or v3
        extensions      [3]  EXPLICIT Extensions OPTIONAL
                             -- If present, version MUST be v3
        }
        
Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }

CertificateSerialNumber  ::=  INTEGER

Validity ::= SEQUENCE {
        notBefore      Time,
        notAfter       Time }

Time ::= CHOICE {
        utcTime        UTCTime,
        generalTime    GeneralizedTime }

UniqueIdentifier  ::=  BIT STRING

SubjectPublicKeyInfo  ::=  SEQUENCE  {
        algorithm            AlgorithmIdentifier,
        subjectPublicKey     BIT STRING  }

Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension

Extension  ::=  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 0
	serial = BN_bn2hex(bignum);  //大数转16进制
	if (NULL == serial)
	{
		LOG(ERROR) << "openSSLCert_get_SN, ERR_R_BN_bn2hex.";
		ret = SAR_UnknownErr;
		goto FREE_MEMORY;
	}
#else
	serial = BN_bn2dec(bignum);  //大数转整数字符串
	if (NULL == serial)
	{
		LError("openSSLCert_get_SN failed, ERR_R_BN_bn2dec.");
		ret = SAR_UnknownErr;
		goto FREE_MEMORY;
	}
#endif
	BN_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=AIDIMCENTITYID
	memset(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=AIDIMCENTITYID
	memset(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 X509
	timeNotBefore = X509_get_notBefore(pX509);
	if (NULL == timeNotBefore)
	{
		LError("X509_get_notBefore failure.");
		return SAR_IndataErr;
	}
	//ASN1_Time to time_t
	lResult = 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_t
	lResult = 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;

#endif

	return 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;
}

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

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值