C语言操作WINDOWS系统存储区数字证书相关函数详解及实例
C语言操作WINDOWS系统存储区数字证书相关函数详解及实例
以下代码使用C++实现遍历存储区证书及使用UI选择一个证书
--使用CertOpenSystemStore打开证书存储区.
--在循环中,使用CertEnumCertificatesInStore.枚举所有存储区中的证书.
--使用CryptUIDlgViewContext显示一个证书.
--使用CertGetNameString取得证书主题名称.
--在循环中,使用CertEnumCertificateContextProperties获取与证书关联的所有属性标识.
--使用CertGetCertificateContextProperty获取每一个标识值.
--使用CryptUIDlgSelectCertificateFromStore以UI的方式列出存储区所有证书并提示用户选择其中一个.
--使用CertCloseStore关闭存储区.
函数详解
1.CertOpenSystemStore
HCERTSTOREWINAPICertOpenSystemStore(
__inHCRYPTPROV_LEGACYhprov,//CSP句柄,一般设置为NULL
__inLPTCSTRszSubsystemProtocol//有四种类型,CA:认证机构证书;MY:关联私钥的证书存储区;ROOT:根证书;SPC:SoftwarePublisherCertificate.
);
如果成功此函数函数一个证书存储区的句柄,否则返回NULL,证书存储区被打开后所有标准证书存储函数均可使用,使用完毕后请用CertCloseStore关闭存储区
2.CertEnumCertificatesInStore
PCCERT_CONTEXTWINAPICertEnumCertificatesInStore(
__inHCERTSTOREhCertStore,
__inPCCERT_CONTEXTpPrevCertContext
);
hCertStore:存储区句柄
pPrevCertContext:指向先前创立的证书上下文CERT_CONTEXT结构体,这个参数必须先置为NULL才能获取第一个证书
3.CryptUIDlgViewContext
列出一个证书,CTL或CRL上下文
BOOLWINAPICryptUIDlgViewContext(
__inDWORDdwContextType,
__inconstvoidpvContext,
__inHWNDhwnd,
__inLPCWSTRpwszTitle,
__inDWORDdwFlags,
__invoidpvReserved
);
dwContextType:上下文的类型,如下表
Value/Meaning
CERT_STORE_CERTIFICATE_CONTEXT/PCCERT_CONTEXT
CERT_STORE_CRL_CONTEXT/PCCRL_CONTEXT
CERT_STORE_CTL_CONTEXT/PCCTL_CONTEXT
pvContext:指向列出的证书,CTL或CRL上下文的指针
hwnd:窗口显示句柄
pwszTitle:显示标题字符串
dwFlags:一般设置为0
pvReserved:保留
4.CertGetNameString
从一个证书的CERT_CONTEXT结构体中取得主题或颁发者名称
DWORDWINAPICertGetNameString(
__inPCCERT_CONTEXTpCertContext,
__inDWORDdwType,
__inDWORDdwFlags,
__invoidpvTypePara,
__outLPTSTRpszNameString,
__inDWORDcchNameString
);
dwType:名称的输出格式
CERT_NAME_EMAIL_TYPE:如果证书有主题可选名称扩展或颁发者名称,使用rfc822Name选项.如果在扩展里没有发现rfc822Name选项,使用该EmailOID的主题名
称域.如果rfc822Name或theEmailOID均没发现,使用string.否则返回空值(returnedcharactercountis1).pvTypePara不使用,设置为NULL.
CERT_NAME_RDN_TYPE:调用CertNameToStr转换主题名称BLOB.pvTypeParapointstoaDWORDcontainingthedwStrTyp epassedtoCertNameToStr.如果主
题名称域为空且证书拥有一个主题可选扩展使用来自CertNameToStr的第一个目录名称
CERT_NAME_ATTR_TYPE:例如,如果pvTypePara值为szOID_COMMON_NAME,使用主题名称成员,如果主题名称成员为空且证书拥有一个可选名称扩展,使用第一个目录名称选项
CERT_NAME_SIMPLE_DISPLAY_TYPE:使用下列顺序szOID_COMMON_NAME, szOID_ORGANIZATIONAL_UNIT_NAME,s zOID_ORGANIZATION_NAME,orszOID_RSA_emailAddr如果其中一个属性没有找到,使用主题可选名称扩展,如果这些都不匹配则使用第一个属性
CERT_NAME_FRIENDLY_DISPLAY_TYPE
CERT_NAME_DNS_TYPE
CERT_NAME_URL_TYPE
CERT_NAME_UPN_TYPE
5.CertEnumCertificateContextProperties
DWORDWINAPICertEnumCertificateContextProperties(
__inPCCERT_CONTEXTpCertContext,
__inDWORDdwPropId//取得第一个属性该值设为0,取得接下来的属性该值为此函数所返回
);
6.CertGetCertificateContextProperty
BOOLWINAPICertGetCertificateContextProperty(
__inPCCERT_CONTEXTpCertContext,
__inDWORDdwPropId,
__outvoidpvData,
__inoutDWORDpcbData
);
该获取证书属性信息,详细请参考http://msdn.microsoft.com/en-us/library/aa376079(V S.85).aspx
7.CryptUIDlgSelectCertificateFromStore
PCCERT_CONTEXTWINAPICryptUIDlgSelectCertificateFro mStore(
__inHCERTSTOREhCertStore,
__inHWNDhwnd,
__in_optLPCWSTRpwszTitle,
__in_optLPCWSTRpwszDisplayString,
__inDWORDdwDontUseColumn,
__inDWORDdwFlags,
__invoidpvReserved
);
弹出一个对话框,允许用户从指定存储目录中选择一个证书
代码[综合]:VC++6下面调试成功
#i nclude<stdio.h>
#i nclude<windows.h>
#i nclude<wincrypt.h>
#i nclude<cryptuiapi.h>//需要装PLATFORMSDK
#i nclude<tchar.h>
#pragmacomment(lib,"crypt32.lib")
#pragmacomment(lib,"cryptui.lib")
#defineMY_ENCODING_TYPE(PKCS_7_ASN_ENCODING|X509_A SN_ENCODING)
voidMyHandleError(chars);
voidmain(void)
{
HCERTSTOREhCertStore;
PCCERT_CONTEXTpCertContext=NULL;
charpszNameString[256];
charpszStoreName[256]="MY";
DWORDdwPropId=0;
charthumb[100]="";
chartemstring[10];
pCertContext=NULL;
if(hCertStore=CertOpenSystemStore(
NULL,
pszStoreName))
{
fprintf(stderr,"Thesstorehasbeenopened.\n",pszStor eName);
}
else
{
MyHandleError("Thestorewasnotopened.");
}
//使用CertEnumCertificatesInStore从存储区获取证书,pCertContext必须置为NULL才能找到第一个证书
while(pCertContext=CertEnumCertificatesInStore(
hCertStore,
pCertContext))
{
//打印证书名称
if(CertGetNameString(
pCertContext,
CERT_NAME_RDN_TYPE,
0,
NULL,
pszNameString,
128))
printf("\nCertificatefors\n",pszNameString);
//遍历指定证书所有属性标识
while(dwPropId=CertEnumCertificateContextPropertie s(
pCertContext,//所列出的证书属性的上下文
dwPropId))//dwPropId值必须先置为0
{
//循环开始执行,属性值被找到
printf("Property#dfound->",dwPropId);
//------------------------------------------------ -------------------
//Indicatethekindofpropertyfound.
switch(dwPropId)
{
caseCERT_FRIENDLY_NAME_PROP_ID:
{
printf("Displayname:");
break;
}
caseCERT_SIGNATURE_HASH_PROP_ID:
{
printf("Signaturehashidentifier");
break;
}
caseCERT_KEY_PROV_HANDLE_PROP_ID:
{
printf("KEYPROVEHANDLE");
break;
}
caseCERT_KEY_PROV_INFO_PROP_ID:
{
printf("KEYPROVINFOPROPID");
break;
}
caseCERT_SHA1_HASH_PROP_ID:
{
printf("SHA1HASHidentifier");
break;
}
caseCERT_MD5_HASH_PROP_ID:
{
printf("md5hashidentifier");
break;
}
caseCERT_KEY_CONTEXT_PROP_ID:
{
printf("KEYCONTEXTPROPidentifier");
break;
}
caseCERT_KEY_SPEC_PROP_ID:
{
printf("KEYSPECPROPidentifier");
break;
}
caseCERT_ENHKEY_USAGE_PROP_ID:
{
printf("ENHKEYUSAGEPROPidentifier");
break;
}
caseCERT_NEXT_UPDATE_LOCATION_PROP_ID:
{
printf("NEXTUPDATELOCATIONPROPidentifier");
break;
}
caseCERT_PVK_FILE_PROP_ID:
{
printf("PVKFILEPROPidentifier");
break;
}
caseCERT_DESCRIPTION_PROP_ID:
{
printf("DESCRIPTIONPROPidentifier");
break;
}
caseCERT_ACCESS_STATE_PROP_ID:
{
printf("ACCESSSTATEPROPidentifier");
break;
}
caseCERT_SMART_CARD_DATA_PROP_ID:
{
printf("SMART_CARDDATAPROPidentifier");
break;
}
caseCERT_EFS_PROP_ID:
{
printf("EFSPROPidentifier");
break;
}
caseCERT_FORTEZZA_DATA_PROP_ID:
{
printf("FORTEZZADATAPROPidentifier");
break;
}
caseCERT_ARCHIVED_PROP_ID:
{
printf("ARCHIVEDPROPidentifier");
break;
}
caseCERT_KEY_IDENTIFIER_PROP_ID:
{
printf("KEYIDENTIFIERPROPidentifier");
break;
}
caseCERT_AUTO_ENROLL_PROP_ID:
{
printf("AUTOENROLLidentifier.");
break;
}
}//Endswitch.
printf("\n");
}//Endinnerwhile.
}//Endouterwhile.
//------------------------------------------------ -------------------
//Selectanewcertificatebyusingtheuserinterface.
//使用UI选择一个新证书
if(!(pCertContext=CryptUIDlgSelectCertificateFromS tore(
hCertStore,
NULL,
NULL,
NULL,
CRYPTUI_SELECT_LOCATION_COLUMN,
0,
NULL)))
{
MyHandleError("SelectUIfailed.");
}
else
{
//显示名称
if(CertGetNameString(
pCertContext,
CERT_NAME_RDN_TYPE,
0,
NULL,
pszNameString,
128))
{
printf("\nCertificatefors\n",pszNameString);
LPBYTEpEncodedBytes=NULL;
LPBYTEpHash;
DWORDcbData,i;
pHash=NULL;
cbData=http://blog.soso.com/qz.q/0;
CertGetCertificateContextProperty(pCertContext,CER T_HASH_PROP_ID,NULL,&cbData);
if(cbData=http://blog.soso.com/qz.q/=0)
{
MyHandleError("CertGetCertificateContextProperty1f ailed");
}
pHash=(LPBYTE)HeapAlloc(GetProcessHeap(),0,cbData) ;
if(pHash==NULL)
{
MyHandleError("HeapAllocfailed");
}
if(!CertGetCertificateContextProperty(pCertContext ,CERT_HASH_PROP_ID,pHash,&cbData))
{
MyHandleError("CertGetCertificateContextProperty2f ailed");
}
printf("CERT_HASH_PROP_IDLengthisd\n",cbData);
for(i=0;i<cbData;i++)
{
sprintf(temstring,"02x",pHash);
strcat(thumb,temstring);
}
printf("Thethumbiss",thumb);
}
else
fprintf(stderr,"CertGetNamefailed.\n");
}
//------------------------------------------------ -------------------
//Cleanup.
CertFreeCertificateContext(pCertContext);
CertCloseStore(hCertStore,0);
}//Endofmain.
voidMyHandleError(LPTSTRpsz)
{
_ftprintf(stderr,TEXT("Anerroroccurredintheprogram .\n"));
_ftprintf(stderr,TEXT("s\n"),psz);
_ftprintf(stderr,TEXT("Errornumberx.\n"),GetLastEr ror());
_ftprintf(stderr,TEXT("Programterminating.\n"));
exit(1);
}//EndofMyHandleError.
以下代码使用C++实现遍历存储区证书及使用UI选择一个证书
--使用CertOpenSystemStore打开证书存储区.
--在循环中,使用CertEnumCertificatesInStore.枚举所有存储区中的证书.
--使用CryptUIDlgViewContext显示一个证书.
--使用CertGetNameString取得证书主题名称.
--在循环中,使用CertEnumCertificateContextProperties获取与证书关联的所有属性标识.
--使用CertGetCertificateContextProperty获取每一个标识值.
--使用CryptUIDlgSelectCertificateFromStore以UI的方式列出存储区所有证书并提示用户选择其中一个.
--使用CertCloseStore关闭存储区.
函数详解
1.CertOpenSystemStore
HCERTSTOREWINAPICertOpenSystemStore(
__inHCRYPTPROV_LEGACYhprov,//CSP句柄,一般设置为NULL
__inLPTCSTRszSubsystemProtocol//有四种类型,CA:认证机构证书;MY:关联私钥的证书存储区;ROOT:根证书;SPC:SoftwarePublisherCertificate.
);
如果成功此函数函数一个证书存储区的句柄,否则返回NULL,证书存储区被打开后所有标准证书存储函数均可使用,使用完毕后请用CertCloseStore关闭存储区
2.CertEnumCertificatesInStore
PCCERT_CONTEXTWINAPICertEnumCertificatesInStore(
__inHCERTSTOREhCertStore,
__inPCCERT_CONTEXTpPrevCertContext
);
hCertStore:存储区句柄
pPrevCertContext:指向先前创立的证书上下文CERT_CONTEXT结构体,这个参数必须先置为NULL才能获取第一个证书
3.CryptUIDlgViewContext
列出一个证书,CTL或CRL上下文
BOOLWINAPICryptUIDlgViewContext(
__inDWORDdwContextType,
__inconstvoidpvContext,
__inHWNDhwnd,
__inLPCWSTRpwszTitle,
__inDWORDdwFlags,
__invoidpvReserved
);
dwContextType:上下文的类型,如下表
Value/Meaning
CERT_STORE_CERTIFICATE_CONTEXT/PCCERT_CONTEXT
CERT_STORE_CRL_CONTEXT/PCCRL_CONTEXT
CERT_STORE_CTL_CONTEXT/PCCTL_CONTEXT
pvContext:指向列出的证书,CTL或CRL上下文的指针
hwnd:窗口显示句柄
pwszTitle:显示标题字符串
dwFlags:一般设置为0
pvReserved:保留
4.CertGetNameString
从一个证书的CERT_CONTEXT结构体中取得主题或颁发者名称
DWORDWINAPICertGetNameString(
__inPCCERT_CONTEXTpCertContext,
__inDWORDdwType,
__inDWORDdwFlags,
__invoidpvTypePara,
__outLPTSTRpszNameString,
__inDWORDcchNameString
);
dwType:名称的输出格式
CERT_NAME_EMAIL_TYPE:如果证书有主题可选名称扩展或颁发者名称,使用rfc822Name选项.如果在扩展里没有发现rfc822Name选项,使用该EmailOID的主题名
称域.如果rfc822Name或theEmailOID均没发现,使用string.否则返回空值(returnedcharactercountis1).pvTypePara不使用,设置为NULL.
CERT_NAME_RDN_TYPE:调用CertNameToStr转换主题名称BLOB.pvTypeParapointstoaDWORDcontainingthedwStrTyp epassedtoCertNameToStr.如果主
题名称域为空且证书拥有一个主题可选扩展使用来自CertNameToStr的第一个目录名称
CERT_NAME_ATTR_TYPE:例如,如果pvTypePara值为szOID_COMMON_NAME,使用主题名称成员,如果主题名称成员为空且证书拥有一个可选名称扩展,使用第一个目录名称选项
CERT_NAME_SIMPLE_DISPLAY_TYPE:使用下列顺序szOID_COMMON_NAME, szOID_ORGANIZATIONAL_UNIT_NAME,s zOID_ORGANIZATION_NAME,orszOID_RSA_emailAddr如果其中一个属性没有找到,使用主题可选名称扩展,如果这些都不匹配则使用第一个属性
CERT_NAME_FRIENDLY_DISPLAY_TYPE
CERT_NAME_DNS_TYPE
CERT_NAME_URL_TYPE
CERT_NAME_UPN_TYPE
5.CertEnumCertificateContextProperties
DWORDWINAPICertEnumCertificateContextProperties(
__inPCCERT_CONTEXTpCertContext,
__inDWORDdwPropId//取得第一个属性该值设为0,取得接下来的属性该值为此函数所返回
);
6.CertGetCertificateContextProperty
BOOLWINAPICertGetCertificateContextProperty(
__inPCCERT_CONTEXTpCertContext,
__inDWORDdwPropId,
__outvoidpvData,
__inoutDWORDpcbData
);
该获取证书属性信息,详细请参考http://msdn.microsoft.com/en-us/library/aa376079(V S.85).aspx
7.CryptUIDlgSelectCertificateFromStore
PCCERT_CONTEXTWINAPICryptUIDlgSelectCertificateFro mStore(
__inHCERTSTOREhCertStore,
__inHWNDhwnd,
__in_optLPCWSTRpwszTitle,
__in_optLPCWSTRpwszDisplayString,
__inDWORDdwDontUseColumn,
__inDWORDdwFlags,
__invoidpvReserved
);
弹出一个对话框,允许用户从指定存储目录中选择一个证书
代码[综合]:VC++6下面调试成功
#i nclude<stdio.h>
#i nclude<windows.h>
#i nclude<wincrypt.h>
#i nclude<cryptuiapi.h>//需要装PLATFORMSDK
#i nclude<tchar.h>
#pragmacomment(lib,"crypt32.lib")
#pragmacomment(lib,"cryptui.lib")
#defineMY_ENCODING_TYPE(PKCS_7_ASN_ENCODING|X509_A SN_ENCODING)
voidMyHandleError(chars);
voidmain(void)
{
HCERTSTOREhCertStore;
PCCERT_CONTEXTpCertContext=NULL;
charpszNameString[256];
charpszStoreName[256]="MY";
DWORDdwPropId=0;
charthumb[100]="";
chartemstring[10];
pCertContext=NULL;
if(hCertStore=CertOpenSystemStore(
NULL,
pszStoreName))
{
fprintf(stderr,"Thesstorehasbeenopened.\n",pszStor eName);
}
else
{
MyHandleError("Thestorewasnotopened.");
}
//使用CertEnumCertificatesInStore从存储区获取证书,pCertContext必须置为NULL才能找到第一个证书
while(pCertContext=CertEnumCertificatesInStore(
hCertStore,
pCertContext))
{
//打印证书名称
if(CertGetNameString(
pCertContext,
CERT_NAME_RDN_TYPE,
0,
NULL,
pszNameString,
128))
printf("\nCertificatefors\n",pszNameString);
//遍历指定证书所有属性标识
while(dwPropId=CertEnumCertificateContextPropertie s(
pCertContext,//所列出的证书属性的上下文
dwPropId))//dwPropId值必须先置为0
{
//循环开始执行,属性值被找到
printf("Property#dfound->",dwPropId);
//------------------------------------------------ -------------------
//Indicatethekindofpropertyfound.
switch(dwPropId)
{
caseCERT_FRIENDLY_NAME_PROP_ID:
{
printf("Displayname:");
break;
}
caseCERT_SIGNATURE_HASH_PROP_ID:
{
printf("Signaturehashidentifier");
break;
}
caseCERT_KEY_PROV_HANDLE_PROP_ID:
{
printf("KEYPROVEHANDLE");
break;
}
caseCERT_KEY_PROV_INFO_PROP_ID:
{
printf("KEYPROVINFOPROPID");
break;
}
caseCERT_SHA1_HASH_PROP_ID:
{
printf("SHA1HASHidentifier");
break;
}
caseCERT_MD5_HASH_PROP_ID:
{
printf("md5hashidentifier");
break;
}
caseCERT_KEY_CONTEXT_PROP_ID:
{
printf("KEYCONTEXTPROPidentifier");
break;
}
caseCERT_KEY_SPEC_PROP_ID:
{
printf("KEYSPECPROPidentifier");
break;
}
caseCERT_ENHKEY_USAGE_PROP_ID:
{
printf("ENHKEYUSAGEPROPidentifier");
break;
}
caseCERT_NEXT_UPDATE_LOCATION_PROP_ID:
{
printf("NEXTUPDATELOCATIONPROPidentifier");
break;
}
caseCERT_PVK_FILE_PROP_ID:
{
printf("PVKFILEPROPidentifier");
break;
}
caseCERT_DESCRIPTION_PROP_ID:
{
printf("DESCRIPTIONPROPidentifier");
break;
}
caseCERT_ACCESS_STATE_PROP_ID:
{
printf("ACCESSSTATEPROPidentifier");
break;
}
caseCERT_SMART_CARD_DATA_PROP_ID:
{
printf("SMART_CARDDATAPROPidentifier");
break;
}
caseCERT_EFS_PROP_ID:
{
printf("EFSPROPidentifier");
break;
}
caseCERT_FORTEZZA_DATA_PROP_ID:
{
printf("FORTEZZADATAPROPidentifier");
break;
}
caseCERT_ARCHIVED_PROP_ID:
{
printf("ARCHIVEDPROPidentifier");
break;
}
caseCERT_KEY_IDENTIFIER_PROP_ID:
{
printf("KEYIDENTIFIERPROPidentifier");
break;
}
caseCERT_AUTO_ENROLL_PROP_ID:
{
printf("AUTOENROLLidentifier.");
break;
}
}//Endswitch.
printf("\n");
}//Endinnerwhile.
}//Endouterwhile.
//------------------------------------------------ -------------------
//Selectanewcertificatebyusingtheuserinterface.
//使用UI选择一个新证书
if(!(pCertContext=CryptUIDlgSelectCertificateFromS tore(
hCertStore,
NULL,
NULL,
NULL,
CRYPTUI_SELECT_LOCATION_COLUMN,
0,
NULL)))
{
MyHandleError("SelectUIfailed.");
}
else
{
//显示名称
if(CertGetNameString(
pCertContext,
CERT_NAME_RDN_TYPE,
0,
NULL,
pszNameString,
128))
{
printf("\nCertificatefors\n",pszNameString);
LPBYTEpEncodedBytes=NULL;
LPBYTEpHash;
DWORDcbData,i;
pHash=NULL;
cbData=http://blog.soso.com/qz.q/0;
CertGetCertificateContextProperty(pCertContext,CER T_HASH_PROP_ID,NULL,&cbData);
if(cbData=http://blog.soso.com/qz.q/=0)
{
MyHandleError("CertGetCertificateContextProperty1f ailed");
}
pHash=(LPBYTE)HeapAlloc(GetProcessHeap(),0,cbData) ;
if(pHash==NULL)
{
MyHandleError("HeapAllocfailed");
}
if(!CertGetCertificateContextProperty(pCertContext ,CERT_HASH_PROP_ID,pHash,&cbData))
{
MyHandleError("CertGetCertificateContextProperty2f ailed");
}
printf("CERT_HASH_PROP_IDLengthisd\n",cbData);
for(i=0;i<cbData;i++)
{
sprintf(temstring,"02x",pHash);
strcat(thumb,temstring);
}
printf("Thethumbiss",thumb);
}
else
fprintf(stderr,"CertGetNamefailed.\n");
}
//------------------------------------------------ -------------------
//Cleanup.
CertFreeCertificateContext(pCertContext);
CertCloseStore(hCertStore,0);
}//Endofmain.
voidMyHandleError(LPTSTRpsz)
{
_ftprintf(stderr,TEXT("Anerroroccurredintheprogram .\n"));
_ftprintf(stderr,TEXT("s\n"),psz);
_ftprintf(stderr,TEXT("Errornumberx.\n"),GetLastEr ror());
_ftprintf(stderr,TEXT("Programterminating.\n"));
exit(1);
}//EndofMyHandleError.