您的位置:首页 > 其它

使用CryptoAPI获取证书扩展属性之二:“密钥用法”和"增强型密钥用法"

2015-09-09 10:18 716 查看
上篇文章讲述了如何使用CryptoAPI获取证书的“基本约束”扩展属性:使用CryptoAPI获取证书扩展属性之一:“基本约束”

今天继续讲述如何获取“密钥用法”和“增强型密钥用法”这两个扩展属性。"密钥用法"限定了该证书的用途类型,主要分数据签名和数据加密两大类(有的证书同时具有这两类用途)。如下图所示,该证书的用途类型为“数据签名”:



而“增强型密钥用法”属性进一步指明具体用途, 如下图所以,该证书的具体用途为“邮件签名”和“身份验证签名”:



通过CryptoAPI获取这两个扩展属性,具体步骤如下:

1、调用函数CertFindExtension()找到扩展对象

2、使用函数CryptDecodeObject()解码对象,得到属性结构体。其中:

“密钥用法”的结构用CRYPT_BIT_BLOB表示,其定义为:

typedef struct _CRYPT_BIT_BLOB {
    DWORD   cbData;
    BYTE    *pbData;
    DWORD   cUnusedBits;
} CRYPT_BIT_BLOB, *PCRYPT_BIT_BLOB;
其成员变量pbData[0]和pbData[1]表明了用途类型,可以是下面定义的一种、或几种用途的组合。

// Byte[0]
#define CERT_DIGITAL_SIGNATURE_KEY_USAGE     0x80
#define CERT_NON_REPUDIATION_KEY_USAGE       0x40
#define CERT_KEY_ENCIPHERMENT_KEY_USAGE      0x20
#define CERT_DATA_ENCIPHERMENT_KEY_USAGE     0x10
#define CERT_KEY_AGREEMENT_KEY_USAGE         0x08
#define CERT_KEY_CERT_SIGN_KEY_USAGE         0x04
#define CERT_OFFLINE_CRL_SIGN_KEY_USAGE      0x02
#define CERT_CRL_SIGN_KEY_USAGE              0x02
#define CERT_ENCIPHER_ONLY_KEY_USAGE         0x01
// Byte[1]
#define CERT_DECIPHER_ONLY_KEY_USAGE         0x80
而"增强型密钥用法"有自己专用的结构体,定义如下:

typedef struct _CTL_USAGE {
    DWORD               cUsageIdentifier;
    LPSTR               *rgpszUsageIdentifier;      // array of pszObjId
} CTL_USAGE, *PCTL_USAGE,
CERT_ENHKEY_USAGE, *PCERT_ENHKEY_USAGE;
其中:

cUsageIdentifier:指明用法标示的个数

rgpszUsageIdentifier:用法标示数组,常见的增强型用法标示定义如下(完整的定义请见文件wincrypt.h):

//+-------------------------------------------------------------------------
//  Enhanced Key Usage (Purpose) Object Identifiers
//--------------------------------------------------------------------------
#define szOID_PKIX_KP                   "1.3.6.1.5.5.7.3"

// Consistent key usage bits: DIGITAL_SIGNATURE, KEY_ENCIPHERMENT
// or KEY_AGREEMENT
#define szOID_PKIX_KP_SERVER_AUTH       "1.3.6.1.5.5.7.3.1"

// Consistent key usage bits: DIGITAL_SIGNATURE
#define szOID_PKIX_KP_CLIENT_AUTH       "1.3.6.1.5.5.7.3.2"

// Consistent key usage bits: DIGITAL_SIGNATURE
#define szOID_PKIX_KP_CODE_SIGNING      "1.3.6.1.5.5.7.3.3"

// Consistent key usage bits: DIGITAL_SIGNATURE, NON_REPUDIATION and/or
// (KEY_ENCIPHERMENT or KEY_AGREEMENT)
#define szOID_PKIX_KP_EMAIL_PROTECTION  "1.3.6.1.5.5.7.3.4"

// Consistent key usage bits: DIGITAL_SIGNATURE and/or
// (KEY_ENCIPHERMENT or KEY_AGREEMENT)
#define szOID_PKIX_KP_IPSEC_END_SYSTEM  "1.3.6.1.5.5.7.3.5"

// Consistent key usage bits: DIGITAL_SIGNATURE and/or
// (KEY_ENCIPHERMENT or KEY_AGREEMENT)
#define szOID_PKIX_KP_IPSEC_TUNNEL      "1.3.6.1.5.5.7.3.6"

// Consistent key usage bits: DIGITAL_SIGNATURE and/or
// (KEY_ENCIPHERMENT or KEY_AGREEMENT)
#define szOID_PKIX_KP_IPSEC_USER        "1.3.6.1.5.5.7.3.7"

// Consistent key usage bits: DIGITAL_SIGNATURE or NON_REPUDIATION
#define szOID_PKIX_KP_TIMESTAMP_SIGNING "1.3.6.1.5.5.7.3.8"

// OCSP response signer
#define szOID_PKIX_KP_OCSP_SIGNING      "1.3.6.1.5.5.7.3.9"

// Following extension is present to indicate no revocation checking
// for the OCSP signer certificate
#define szOID_PKIX_OCSP_NOCHECK         "1.3.6.1.5.5.7.48.1.5"

// OCSP Nonce
#define szOID_PKIX_OCSP_NONCE		"1.3.6.1.5.5.7.48.1.2"

// IKE (Internet Key Exchange) Intermediate KP for an IPsec end entity.
// Defined in draft-ietf-ipsec-pki-req-04.txt, December 14, 1999.
#define szOID_IPSEC_KP_IKE_INTERMEDIATE "1.3.6.1.5.5.8.2.2"


3、解析结构体中的值,得到具体含义

基于以上过程,下面给出获取“密钥用法”和“增强型密钥用法”两个扩展属性的完整代码。“密钥用法”扩展属性的获取代码如下:

ULONG CCSPCertificate::_GetExtKeyUsage(PCCERT_CONTEXT pCertContext,LPSTR lpscProperty,ULONG* pulLen)
{
	ULONG ulRes = 0;
	ULONG ulDataLen = 512;
	ULONG ulPropertyLen = 512;
	BYTE btData[512] = {0};
	CHAR csProperty[512] = {0};
	PCERT_EXTENSION pCertExt = NULL;

	if (!pCertContext)
	{
		return CERT_ERR_INVILIDCALL;
	}
	if (!pulLen)
	{
		return CERT_ERR_INVALIDPARAM;
	}
	
	pCertExt = CertFindExtension(szOID_KEY_USAGE, pCertContext->pCertInfo->cExtension, pCertContext->pCertInfo->rgExtension); 
	if (!pCertExt)
	{
		return CERT_ERR_ATTR_NOTEXIST;
	}

	PCRYPT_BIT_BLOB pBlob = (PCRYPT_BIT_BLOB)btData;
	if (CryptDecodeObject(	GLOBAL_ENCODING_TYPE, szOID_KEY_USAGE, 
							pCertExt->Value.pbData, pCertExt->Value.cbData, 
							CRYPT_DECODE_NOCOPY_FLAG, pBlob, &ulDataLen))
	{
		USHORT nValue = 0;
		CHAR csValue[32] = {0};
		if (pBlob->cbData == 1) nValue = pBlob->pbData[0];
		else nValue = pBlob->pbData[0] | (pBlob->pbData[1] << 8);
		sprintf_s(csValue, 32, "(%x)", nValue);
		if (pBlob->pbData[0] & CERT_DIGITAL_SIGNATURE_KEY_USAGE)
		{
			strcat_s(csProperty, 512, "Digital Signature, ");
		}
		if (pBlob->pbData[0] & CERT_NON_REPUDIATION_KEY_USAGE)
		{
			strcat_s(csProperty, 512, "Non-Repudiation, ");
		}
		if (pBlob->pbData[0] & CERT_KEY_ENCIPHERMENT_KEY_USAGE)
		{
			strcat_s(csProperty, 512, "Key Encipherment, ");
		}
		if (pBlob->pbData[0] & CERT_DATA_ENCIPHERMENT_KEY_USAGE)
		{
			strcat_s(csProperty, 512, "Data  Encipherment, ");
		}
		if (pBlob->pbData[0] & CERT_KEY_AGREEMENT_KEY_USAGE)
		{
			strcat_s(csProperty, 512, "Key  Agreement, ");
		}
		if (pBlob->pbData[0] & CERT_KEY_CERT_SIGN_KEY_USAGE)
		{
			strcat_s(csProperty, 512, "Certificate Signature, ");
		}
		if (pBlob->pbData[0] & CERT_OFFLINE_CRL_SIGN_KEY_USAGE)
		{
			strcat_s(csProperty, 512, "Offline CRL Signature, ");
		}
		if (pBlob->pbData[0] & CERT_CRL_SIGN_KEY_USAGE)
		{
			strcat_s(csProperty, 512, "CRL Signature, ");
		}
		if (pBlob->pbData[0] & CERT_ENCIPHER_ONLY_KEY_USAGE)
		{
			strcat_s(csProperty, 512, "Only encypt data, ");
		}
		if (pBlob->pbData[1] & CERT_DECIPHER_ONLY_KEY_USAGE)
		{
			strcat_s(csProperty, 512, "Only decypt data, ");
		}
			
		strcat_s(csProperty, 512, csValue);
	}
	else
	{
		return GetLastError();
	}
	
	if (!lpscProperty)
	{
		*pulLen = strlen(csProperty) + 1;
	}
	if (*pulLen < (strlen(csProperty) + 1))
	{
		return CERT_ERR_BUFFER_TOO_SMALL;
	}
	strcpy_s(lpscProperty, *pulLen, csProperty);

	return CERT_ERR_OK;
}
“增强型密钥用法”的获取代码如下:

ULONG CCSPCertificate::_GetExtEnhancedKeyUsage(PCCERT_CONTEXT pCertContext,LPSTR lpscProperty,ULONG* pulLen)
{
	ULONG ulRes = 0;
	ULONG ulDataLen = 512;
	ULONG ulPropertyLen = 512;
	BYTE btData[512] = {0};
	CHAR csProperty[512] = {0};
	PCERT_EXTENSION pCertExt = NULL;

	if (!pCertContext)
	{
		return CERT_ERR_INVILIDCALL;
	}
	if (!pulLen)
	{
		return CERT_ERR_INVALIDPARAM;
	}
	
	pCertExt = CertFindExtension(szOID_ENHANCED_KEY_USAGE, pCertContext->pCertInfo->cExtension, pCertContext->pCertInfo->rgExtension); 
	if (!pCertExt)
	{
		return CERT_ERR_ATTR_NOTEXIST;
	}
		
	PCERT_ENHKEY_USAGE pEnhanceUsage = (PCERT_ENHKEY_USAGE)btData;
	if (CryptDecodeObject(	GLOBAL_ENCODING_TYPE, szOID_ENHANCED_KEY_USAGE, 
							pCertExt->Value.pbData, pCertExt->Value.cbData, 
							CRYPT_DECODE_NOCOPY_FLAG, pEnhanceUsage, &ulDataLen))
	{
		for (ULONG ulIndex = 0; ulIndex < pEnhanceUsage->cUsageIdentifier; ulIndex++)
		{
			
			if (_stricmp(pEnhanceUsage->rgpszUsageIdentifier[ulIndex], szOID_PKIX_KP_SERVER_AUTH) == 0)
			{
				strcat_s(csProperty, 512, "服务器认证 (");
				strcat_s(csProperty, 512, szOID_PKIX_KP_SERVER_AUTH);
				strcat_s(csProperty, 512, "); ");
			}
			else if (_stricmp(pEnhanceUsage->rgpszUsageIdentifier[ulIndex], szOID_PKIX_KP_CLIENT_AUTH) == 0)
			{
				strcat_s(csProperty, 512, "客户端认证 (");
				strcat_s(csProperty, 512, szOID_PKIX_KP_CLIENT_AUTH);
				strcat_s(csProperty, 512, "); ");
			}
			else if (_stricmp(pEnhanceUsage->rgpszUsageIdentifier[ulIndex], szOID_PKIX_KP_CODE_SIGNING) == 0)
			{
				strcat_s(csProperty, 512, "程序代码签名 (");
				strcat_s(csProperty, 512, szOID_PKIX_KP_CODE_SIGNING);
				strcat_s(csProperty, 512, "); ");
			}
			else if (_stricmp(pEnhanceUsage->rgpszUsageIdentifier[ulIndex], szOID_PKIX_KP_EMAIL_PROTECTION) == 0)
			{
				strcat_s(csProperty, 512, "安全电子邮件 (");
				strcat_s(csProperty, 512, szOID_PKIX_KP_EMAIL_PROTECTION);
				strcat_s(csProperty, 512, "); ");
			}
			else if (_stricmp(pEnhanceUsage->rgpszUsageIdentifier[ulIndex], szOID_PKIX_KP_IPSEC_END_SYSTEM) == 0)
			{
				strcat_s(csProperty, 512, "IP终端系统安全 (");
				strcat_s(csProperty, 512, szOID_PKIX_KP_IPSEC_END_SYSTEM);
				strcat_s(csProperty, 512, "); ");
			}
			else if (_stricmp(pEnhanceUsage->rgpszUsageIdentifier[ulIndex], szOID_PKIX_KP_IPSEC_TUNNEL) == 0)
			{
				strcat_s(csProperty, 512, "IP通道安全 (");
				strcat_s(csProperty, 512, szOID_PKIX_KP_IPSEC_TUNNEL);
				strcat_s(csProperty, 512, "); ");
			}
			else if (_stricmp(pEnhanceUsage->rgpszUsageIdentifier[ulIndex], szOID_PKIX_KP_IPSEC_USER) == 0)
			{
				strcat_s(csProperty, 512, "IP用户安全 (");
				strcat_s(csProperty, 512, szOID_PKIX_KP_IPSEC_USER);
				strcat_s(csProperty, 512, "); ");
			}
			else if (_stricmp(pEnhanceUsage->rgpszUsageIdentifier[ulIndex], szOID_PKIX_KP_TIMESTAMP_SIGNING) == 0)
			{
				strcat_s(csProperty, 512, "时间戳签名 (");
				strcat_s(csProperty, 512, szOID_PKIX_KP_TIMESTAMP_SIGNING);
				strcat_s(csProperty, 512, "); ");
			}
			else if (_stricmp(pEnhanceUsage->rgpszUsageIdentifier[ulIndex], szOID_PKIX_KP_OCSP_SIGNING) == 0)
			{
				strcat_s(csProperty, 512, "OCSP签名 (");
				strcat_s(csProperty, 512, szOID_PKIX_KP_OCSP_SIGNING);
				strcat_s(csProperty, 512, "); ");
			}
			else
			{
				strcat_s(csProperty, 512, "(");
				strcat_s(csProperty, 512, pEnhanceUsage->rgpszUsageIdentifier[ulIndex]);
				strcat_s(csProperty, 512, "); ");
			}
		}
	}
	else
	{
		return GetLastError();
	}		
	
	if (!lpscProperty)
	{
		*pulLen = strlen(csProperty) + 1;
	}
	if (*pulLen < (strlen(csProperty) + 1))
	{
		return CERT_ERR_BUFFER_TOO_SMALL;
	}
	strcpy_s(lpscProperty, *pulLen, csProperty);

	return CERT_ERR_OK;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: