前面通过一系列文章,讲述了如使用CryptoAPI解析证书的基本项,现在我们来看看如何获取证书的扩展项。
目前CA中心颁发的证书,都有一些扩展项属性,用来限定证书的用途、提供颁发者信息、以及CRL的下载地址等等。在下图中,红色区域内的属性都为证书的扩展属性。
在CryptoAPI中,提供了获取这些扩展属性的方法。今天,我们先看看如何获取证书扩展属性中的“基本约束”属性。具体可以通过以下步骤来实现:
1、调用函数CertFindExtension()找到扩展对象
该函数的定义如下:
PCERT_EXTENSION WINAPI CertFindExtension(
_In_ LPCSTR pszObjId,
_In_ DWORD cExtensions,
_In_ CERT_EXTENSION rgExtensions[]
);
其中:
第一个参数pszObjId为对象的ID,要获取“基本约束”扩展对象需要指定为szOID_BASIC_CONSTRAINTS2;
第二个参数是指扩展属性数组的成员个数,由证书信息结构体中的cExtension成员指定;
第三个参数为扩展属性数组,由证书信息结构体中的rgExtension成员指定。
2、使用函数CryptDecodeObject()解码对象,得到属性结构体
在CryptoAPI中,微软为“基本约束”扩展属性定义了结构体,具体如下:
typedef struct _CERT_BASIC_CONSTRAINTS2_INFO {
BOOL fCA;
BOOL fPathLenConstraint;
DWORD dwPathLenConstraint;
} CERT_BASIC_CONSTRAINTS2_INFO, *PCERT_BASIC_CONSTRAINTS2_INFO;
其中:
第一个成员fCA,表明该证书可否作为CA证书签发下一级证书。一般用户证书该值都为FALSE;
第二个成员fPathLenConstraint,表明当作CA证书时,是否有级别限制;
第三个成员dwPathLenConstraint,只有到fPathLenConstraint为TRUE时有效,表明具体可以签发的证书级别。
3、解析结构体中的值
如果我们得到了上面结构体的具体值,就可以根据值来显示“基本约束”的属性了。
完整的解析“基本约束”属性的函数代码如下:
ULONG CCSPCertificate::_GetExtBasicConstraints(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_BASIC_CONSTRAINTS2, pCertContext->pCertInfo->cExtension, pCertContext->pCertInfo->rgExtension);
if (pCertExt)
{
PCERT_BASIC_CONSTRAINTS2_INFO pInfo = (PCERT_BASIC_CONSTRAINTS2_INFO)btData;
if (CryptDecodeObject( GLOBAL_ENCODING_TYPE, szOID_BASIC_CONSTRAINTS2,
pCertExt->Value.pbData, pCertExt->Value.cbData,
CRYPT_DECODE_NOCOPY_FLAG, pInfo, &ulDataLen))
{
if (pInfo->fCA)
{
strcat_s(csProperty, 512, "Subject Type=CA; ");
}
else
{
strcat_s(csProperty, 512, "Subject Type=End Entity; ");
}
if (pInfo->fPathLenConstraint)
{
CHAR csTemp[128] = {0};
sprintf_s(csTemp, 128, "Path Length Constraint=%d", pInfo->dwPathLenConstraint);
strcat_s(csProperty, 512, csTemp);
}
else
{
strcat_s(csProperty, 512, "Path Length Constraint=None");
}
}
else
{
return GetLastError();
}
}
else
{
pCertExt = CertFindExtension(szOID_BASIC_CONSTRAINTS, pCertContext->pCertInfo->cExtension, pCertContext->pCertInfo->rgExtension);
if (pCertExt)
{
PCERT_BASIC_CONSTRAINTS_INFO pInfo = (PCERT_BASIC_CONSTRAINTS_INFO)btData;
if (CryptDecodeObject( GLOBAL_ENCODING_TYPE, szOID_BASIC_CONSTRAINTS,
pCertExt->Value.pbData, pCertExt->Value.cbData,
CRYPT_DECODE_NOCOPY_FLAG, pInfo, &ulDataLen))
{
if (pInfo->SubjectType.pbData[0] & CERT_CA_SUBJECT_FLAG)
{
strcat_s(csProperty, 512, "Subject Type=CA; ");
}
else if (pInfo->SubjectType.pbData[0] & CERT_END_ENTITY_SUBJECT_FLAG)
{
strcat_s(csProperty, 512, "Subject Type=End Entity; ");
}
else
{
strcat_s(csProperty, 512, "Subject Type=Unknown; ");
}
if (pInfo->fPathLenConstraint)
{
CHAR csTemp[128] = {0};
sprintf_s(csTemp, 128, "Path Length Constraint=%d", pInfo->dwPathLenConstraint);
strcat_s(csProperty, 512, csTemp);
}
else
{
strcat_s(csProperty, 512, "Path Length Constraint=None");
}
}
else
{
return GetLastError();
}
}
else
{
return CERT_ERR_ATTR_NOTEXIST;
}
}
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;
}