我有一个独立的 CA,我需要使用 C# 按证书序列号搜索来获取完整的证书 base64 字符串。
已尝试使用 X509Store,尝试使用 CA 名称、主机名\CA 名称以及所有存储名称和存储位置可能的变体
store = new X509Store("my-ca");
store.Open(OpenFlags.ReadOnly);
ret += "Count: " + store.Certificates.Count;
foreach (X509Certificate2 cert in store.Certificates)
{
ret += "cert.SerialNumber: " + cert.SerialNumber;
}
并且还尝试使用CCertView/CCertRequest,此方法返回信息,但它不是完整的证书,当我从CA手动导出时,字符串不相等。
public string GetCertificateBase64Original(string certificateSerialNumber)
{
string certificateBase64 = string.Empty;
try
{
CCertView certView = new CCertViewClass();
certView.OpenConnection(this.nameCA);
certView.SetResultColumnCount(2);
int requestIDColumnIndex = certView.GetColumnIndex(0, "RequestID");
int certificateSerialNumberColumnIndex = certView.GetColumnIndex(0, "SerialNumber");
certView.SetResultColumn(requestIDColumnIndex);
certView.SetResultColumn(certificateSerialNumberColumnIndex);
object objSerialNumber = certificateSerialNumber;
certView.SetRestriction(certificateSerialNumberColumnIndex, CVR_SEEK_EQ, CVR_SORT_NONE, ref objSerialNumber);
IEnumCERTVIEWROW rowsEnum;
rowsEnum = certView.OpenView();
IEnumCERTVIEWCOLUMN objCol;
rowsEnum.Reset();
int requestID = 0;
while (rowsEnum.Next() != -1)
{
objCol = rowsEnum.EnumCertViewColumn();
while (objCol.Next() != -1)
{
if (objCol.GetName() == "RequestID")
{
try
{
requestID = SafeConvert.ToInt(objCol.GetValue(PROPTYPE_STRING));
}
catch
{
}
}
}
}
if (requestID > 0)
{
CCertRequest certRequest = new CCertRequest();
certRequest.GetIssuedCertificate(this.nameCA, requestID, certificateSerialNumber);
certificateBase64 = SafeConvert.ToString(certRequest.GetFullResponseProperty(FR_PROP_FULLRESPONSE, 0, PROPTYPE_BINARY, CR_OUT_BASE64));
}
}
catch
{
}
return (certificateBase64);
}
根本没有成功。
问题是您正在请求包含完整响应的属性FR_PROP_FULLRESPONSE
(IIRC,PKCS#7 消息)。相反,您应该仅请求颁发的证书属性:FR_PROP_ISSUEDCERTIFICATE
。
顺便说一句,不需要ICertRequest
接口调用。为什么不在ICertView
接口调用中将RawCertificate
列放入结果列列表中,然后获取结果?
使用此代码解决
https://blogs.msdn.microsoft.com/alejacma/2012/04/04/how-to-export-issued-certificates-from-a-ca-programatically-c/https://blogs.msdn.microsoft.com/alejacma/2010/05/10/how-to-get-info-from-client-certificates-issued-by-a-ca-c/
public string GetCertificateBase64(string certificateSerialNumber)
{
string certificateBase64 = string.Empty;
try
{
// Variables
CERTADMINLib.CCertView certView = null;
CERTADMINLib.IEnumCERTVIEWROW certViewRow = null;
CERTADMINLib.IEnumCERTVIEWCOLUMN certViewColumn = null;
int iColumnCount = 0;
object objValue = null;
// Connecting to the Certificate Authority
certView = new CERTADMINLib.CCertView();
certView.OpenConnection(this.nameCA);
// Get a column count and place columns into the view
iColumnCount = certView.GetColumnCount(0);
certView.SetResultColumnCount(iColumnCount);
// Place each column in the view.
for (int x = 0; x < iColumnCount; x++)
{
certView.SetResultColumn(x);
}
int certificateSerialNumberColumnIndex = certView.GetColumnIndex(0, "SerialNumber");
object objSerialNumber = certificateSerialNumber;
certView.SetRestriction(certificateSerialNumberColumnIndex, CVR_SEEK_EQ, CVR_SORT_NONE, ref objSerialNumber);
// Open the View and reset the row position
certViewRow = certView.OpenView();
certViewRow.Reset();
// Enumerate Row and Column Information
// Rows (one per cert)
for (int x = 0; certViewRow.Next() != -1; x++)
{
// Columns with the info we need
certViewColumn = certViewRow.EnumCertViewColumn();
while (certViewColumn.Next() != -1)
{
switch (certViewColumn.GetDisplayName())
{
// Binary Certificate
case "Binary Certificate":
objValue = certViewColumn.GetValue(CV_OUT_BASE64);
if (objValue != null)
{
certificateBase64 = objValue.ToString();
}
break;
default:
break;
}
}
}
}
catch (Exception ex)
{
certificateBase64 += Environment.NewLine + "ex: " + ex.Message;
}
return certificateBase64;
}