问题
i've got following C# code for doing what i asked for in subject:
public static void ExportCertificatesToFile(string FileName)
{
stringBuilder builder = new StringBuilder();
X509Store storeMy = new X509Store(StoreName.My);
storeMy.Open(OpenFlags.ReadOnly);
foreach (X509Certificate2 cert in storeMy.Certificates)
{
builder.AppendLine("-----BEGIN CERTIFICATE-----");
builder.AppendLine(Convert.ToBase64String(cert.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks));
builder.AppendLine("-----END CERTIFICATE-----");
}
storeMy.Close();
File.WriteAllText(FileName, builder.ToString());
}
Exactly that i want to archieve with Delphi using CryptoAPI (JwaWinCrypt.pas) I've tried following code:
procedure TForm1.Button1Click(Sender: TObject);
var
hStore: HCERTSTORE;
CertContext: PCertContext;
pszString: PAnsiChar;
pchString: Cardinal;
begin
hStore := CertOpenSystemStore(0, PChar('MY'));
try
CertContext := CertEnumCertificatesInStore(hStore, nil);
while CertContext <> nil do
begin
pszString := '';
pchString := 0;
CryptBinaryToString(CertContext.pbCertEncoded, CertContext.cbCertEncoded, CRYPT_STRING_BASE64, pszString, pchString);
ShowMessage(StrPas(pszString));
CertContext := CertEnumCertificatesInStore(hStore, CertContext);
end;
finally
CertCloseStore(hStore, 0);
end;
end;
Problem is that ShowMessage shows nothing, the string is empty. Has someone an idea what i do wrong?
回答1:
The documentation for CryptBinaryToString says this about the pszString
parameter.
A pointer to a buffer that receives the converted string. To calculate the number of characters that must be allocated to hold the returned string, set this parameter to NULL. The function will place the required number of characters, including the terminating NULL character, in the value pointed to by pcchString.
You are obliged to allocate the buffer so that the API function can populate it. You are failing to do so. In order to proceed you must read the documentation carefully and abide by the requirements of the API.
So you need to call the function like this:
szString: AnsiString;
....
chString := 0;
CryptBinaryToString(CertContext.pbCertEncoded, CertContext.cbCertEncoded,
CRYPT_STRING_BASE64, nil, chString);
SetLength(szString, chString-1);
CryptBinaryToString(CertContext.pbCertEncoded, CertContext.cbCertEncoded,
CRYPT_STRING_BASE64, PAnsiChar(szString), chString);
You should also check the return value of CryptBinaryToString
to detect failures. I omitted that for brevity.
I'm also assuming that yours is an ANSI Delphi. I assumed that because you used PAnsiChar
.
来源:https://stackoverflow.com/questions/14790930/how-to-export-certificate-from-windows-certificate-store-via-cryptoapi-as-base64