上篇文章讲述了如何使用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;
}