THTTPRIO组件,在HTTPWebNode属性中,当您单击ClientCertificate时,Delphi打开一个表单来选择证书并在组件的属性中加载它的信息。这是一个Windows屏幕吗?如果是,我该如何使用它?今天我使用SecureBlackBox在组合框中加载证书,但我想知道是否可以使用此屏幕。 谢谢
更新
我能够使用ms函数CryptUIDlgSelectCertificateFromStore使用JWAPI显示对话框。现在我遇到了函数结果PCCERT_CONTEXT结构的问题。
var
P: Pointer;
Context: PCCERT_CONTEXT;
Issuer: DATA_BLOB;
function GetDataBlobText(Data: DATA_BLOB): string;
begin
SetString(Result, PAnsiChar(Data.pbData), Data.cbData div SizeOf(AnsiChar));
end;
begin
P := CertOpenSystemStore(0, 'MY');
Context := CryptUIDlgSelectCertificateFromStore(P, 0, PChar('test'), nil, CRYPTUI_SELECT_ISSUEDTO_COLUMN, 0, nil);
if Context <> nil then
begin
Issuer := Context.pCertInfo.Issuer;
ShowMessage((GetDataBlobText(Issuer)));
end;
end;
ShowMessage的结果是:
UPDATE2
谢谢@RbMm。 获取ASN编码字段的字符串(Issuer和Subject)
var
P: Pointer;
Context: PCCERT_CONTEXT;
Subject: DATA_BLOB;
SubjectStr: string;
size : Cardinal;
begin
P := CertOpenSystemStore(0, PAnsiChar('MY'));
Context := CryptUIDlgSelectCertificateFromStore(P, 0, 'test', 'select certificate',
CRYPTUI_SELECT_ISSUEDTO_COLUMN, 0, nil);
if Context <> nil then
begin
Subject := Context.pCertInfo.Subject;
size := CertNameToStr(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, @Subject, CERT_X500_NAME_STR, 0, 0);
SetString(SubjectStr, PAnsiChar(Subject.pbData), size);
CertNameToStr(X509_ASN_ENCODING or PKCS_7_ASN_ENCODING, @Subject, CERT_X500_NAME_STR, PAnsiChar(SubjectStr), size);
Result := SubjectStr;
end;
获取原始数据块的字符串(SerialNumber):
var
SerialNumber: CRYPT_INTEGER_BLOB;
size : Cardinal;
s: PWideChar;
ss: string;
begin
SerialNumber := Context.pCertInfo.SerialNumber;
CryptBinaryToStringW(SerialNumber.pbData, SerialNumber.cbData, CRYPT_STRING_HEX, nil, size);
s := AllocMem(SizeOf(Char) * size);
CryptBinaryToStringW(SerialNumber.pbData, SerialNumber.cbData, CRYPT_STRING_HEX, s, size);
ss := s;
showmessage(ss);
FreeMem(s, SizeOf(Char) * size);
答案 0 :(得分:1)
证书中的所有数据blob都已编码。所以你需要解码它。通常使用CryptDecodeObjectEx
api。但是对于Issuer
(即CERT_NAME_BLOB
)解码,您也可以使用CertNameToStrW
。只有在将CERT_NAME_BLOB
结构中的编码名称转换为以空字符结尾的字符串后,才能将其打印出来。 c / c ++ 上的代码示例:
void PrintIssuer(PCCERT_CONTEXT Context)
{
CERT_NAME_BLOB Issuer = Context->pCertInfo->Issuer;
// option #1
if (ULONG len = CertNameToStrW(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &Issuer, CERT_X500_NAME_STR, 0, 0))
{
PWSTR sz = (PWSTR)alloca( len * sizeof(WCHAR));
if (CertNameToStrW(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &Issuer, CERT_X500_NAME_STR, sz, len))
{
DbgPrint("%S\n", sz);
}
}
// option #2
PCERT_NAME_INFO pcni;
ULONG size;
if (CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, X509_NAME, Issuer.pbData, Issuer.cbData,
CRYPT_DECODE_ALLOC_FLAG, 0, &pcni, &size))
{
if (DWORD cRDN = pcni->cRDN)
{
PCERT_RDN rgRDN = pcni->rgRDN;
do
{
if (DWORD cRDNAttr = rgRDN->cRDNAttr)
{
PCERT_RDN_ATTR rgRDNAttr = rgRDN->rgRDNAttr;
do
{
DbgPrint("ObjId = %s\n", rgRDNAttr->pszObjId);
switch (rgRDNAttr->dwValueType)
{
case CERT_RDN_PRINTABLE_STRING:
DbgPrint("Value = %s\n", rgRDNAttr->Value.pbData);
break;
}
} while (rgRDNAttr++, --cRDNAttr);
}
} while (rgRDN++, --cRDN);
}
LocalFree(pcni);
}
}
和输出
CN=***
ObjId = 2.5.4.3
Value = ***
( CN = 和 Value = 之后的字符串相同)
您可以注意到&#34; 2.5.4.3&#34; 是szOID_COMMON_NAME
或&#34; CN&#34; 。所以第一个api在发行者名称之前追加 CN = 。第二个变体按原样返回您的名称,并附加ObjId = 2.5.4.3
将 SerialNumber 转换为可打印的字符串可以采用下一种方式:
CRYPT_INTEGER_BLOB SerialNumber = Context->pCertInfo->SerialNumber;
DWORD cb = 0;
if (CryptBinaryToStringW(SerialNumber.pbData, SerialNumber.cbData, CRYPT_STRING_HEX, 0, &cb))
{
PWSTR sz = (PWSTR)alloca( cb * sizeof(WCHAR));
if (CryptBinaryToStringW(SerialNumber.pbData, SerialNumber.cbData, CRYPT_STRING_HEX, sz, &cb))
{
DbgPrint("%S\n", sz);
}
}