我正在尝试在Windows计算机上创建自签名证书。我希望证书可以导出(甚至是私钥)。但是,我在完成这项任务时遇到了一些困难。
我找到了一些指向WIN32调用的网站。当我在Windows XP上运行代码时,证书存储在个人证书中,可以很好地导出。当我在Windows 7 64位上运行此代码时,我得到的证书没有错误,但证书不可导出。我不能将它用于我为其分配证书的网站。
Certificate.Check(Certificate.NativeMethods.CryptAcquireContextW(
out providerContext,
containerName,
null,
1, // PROV_RSA_FULL
8)); // CRYPT_NEWKEYSET
Certificate.Check(Certificate.NativeMethods.CryptGenKey(
providerContext,
1, // AT_KEYEXCHANGE
1, // CRYPT_EXPORTABLE
out cryptKey));
IntPtr errorStringPtr;
int nameDataLength = 0;
byte[] nameData;
// errorStringPtr gets a pointer into the middle of the x500 string,
// so x500 needs to be pinned until after we've copied the value
// of errorStringPtr.
dataHandle = GCHandle.Alloc(commonName, GCHandleType.Pinned);
if (!Certificate.NativeMethods.CertStrToNameW(
0x00000001, // X509_ASN_ENCODING
dataHandle.AddrOfPinnedObject(),
3, // CERT_X500_NAME_STR = 3
IntPtr.Zero,
null,
ref nameDataLength,
out errorStringPtr))
{
string error = Marshal.PtrToStringUni(errorStringPtr);
throw new ArgumentException(error);
}
nameData = new byte[nameDataLength];
if (!Certificate.NativeMethods.CertStrToNameW(
0x00000001, // X509_ASN_ENCODING
dataHandle.AddrOfPinnedObject(),
3, // CERT_X500_NAME_STR = 3
IntPtr.Zero,
nameData,
ref nameDataLength,
out errorStringPtr))
{
string error = Marshal.PtrToStringUni(errorStringPtr);
throw new ArgumentException(error);
}
Console.WriteLine("THIS IS CHANGED");
dataHandle.Free();
dataHandle = GCHandle.Alloc(nameData, GCHandleType.Pinned);
Certificate.CryptoApiBlob nameBlob = new Certificate.CryptoApiBlob(
nameData.Length,
dataHandle.AddrOfPinnedObject());
Certificate.CryptKeyProviderInformation kpi = new Certificate.CryptKeyProviderInformation();
kpi.ContainerName = containerName;
kpi.ProviderType = 1; // PROV_RSA_FULL
kpi.KeySpec = 1; // AT_KEYEXCHANGE
certContext = Certificate.NativeMethods.CertCreateSelfSignCertificate(
IntPtr.Zero,
ref nameBlob,
0,
ref kpi,
IntPtr.Zero, // default = SHA1RSA
ref startSystemTime,
ref endSystemTime,
IntPtr.Zero);
Certificate.Check(certContext != IntPtr.Zero);
dataHandle.Free();
X509Certificate2 tempCert = new X509Certificate2(certContext);
//result = new X509Certificate2(tempCert.RawData, "", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
result = tempCert;
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
store.Add(result);
store.Close();
注意,Certificate类是一个内部类,它只包含我正在使用的不同静态方法和WIN32定义。这是NativeMethods类定义(显示我正在使用的WIN32 API调用):
internal static class NativeMethods
{
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FileTimeToSystemTime(
[In] ref long fileTime,
out SystemTime systemTime);
[DllImport("AdvApi32.dll", SetLastError = true, ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptAcquireContextW(
out IntPtr providerContext,
[MarshalAs(UnmanagedType.LPWStr)] string container,
[MarshalAs(UnmanagedType.LPWStr)] string provider,
int providerType,
int flags);
[DllImport("AdvApi32.dll", SetLastError = true, ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptReleaseContext(
IntPtr providerContext,
int flags);
[DllImport("AdvApi32.dll", SetLastError = true, ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptGenKey(
IntPtr providerContext,
int algorithmId,
int flags,
out IntPtr cryptKeyHandle);
[DllImport("AdvApi32.dll", SetLastError = true, ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CryptDestroyKey(
IntPtr cryptKeyHandle);
[DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CertStrToNameW(
int certificateEncodingType,
IntPtr x500,
int strType,
IntPtr reserved,
[MarshalAs(UnmanagedType.LPArray)] [Out] byte[] encoded,
ref int encodedLength,
out IntPtr errorString);
[DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
public static extern IntPtr CertCreateSelfSignCertificate(
IntPtr providerHandle,
[In] ref CryptoApiBlob subjectIssuerBlob,
int flags,
[In] ref CryptKeyProviderInformation keyProviderInformation,
IntPtr signatureAlgorithm,
[In] ref SystemTime startTime,
[In] ref SystemTime endTime,
IntPtr extensions);
[DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CertFreeCertificateContext(
IntPtr certificateContext);
[DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
public static extern IntPtr CertOpenStore(
[MarshalAs(UnmanagedType.LPStr)] string storeProvider,
int messageAndCertificateEncodingType,
IntPtr cryptProvHandle,
int flags,
IntPtr parameters);
[DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CertCloseStore(
IntPtr certificateStoreHandle,
int flags);
[DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CertAddCertificateContextToStore(
IntPtr certificateStoreHandle,
IntPtr certificateContext,
int addDisposition,
out IntPtr storeContextPtr);
[DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CertSetCertificateContextProperty(
IntPtr certificateContext,
int propertyId,
int flags,
[In] ref CryptKeyProviderInformation data);
[DllImport("Crypt32.dll", SetLastError = true, ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool PFXExportCertStoreEx(
IntPtr certificateStoreHandle,
ref CryptoApiBlob pfxBlob,
IntPtr password,
IntPtr reserved,
int flags);
}
如果我在32位或64位机器上,这有关系吗?我不知道此时该做些什么。我从以下链接获得此代码:Creating Self Signed Cert in C#
答案 0 :(得分:3)
我发现问题导致我无法导出证书。事实证明,我实际上无法在Windows XP上导出它(我已经看过几次了,但那时我正在调试并且之后没有执行代码导致它中断)。
在清理程序中,密钥集被删除了:
NativeMethods.CryptAcquireContextW(
out providerContext,
containerName,
null,
1, // PROV_RSA_FULL
0x10); // CRYPT_DELETEKEYSET
这会导致证书无法再导出私钥。当此行被注释掉时,证书安装在本地计算机的个人证书存储中。它也被允许导出,因此允许我将IIS配置为指向此证书。