Windows マシンで自己署名証明書を作成しようとしています。証明書をエクスポート可能にしたい (秘密鍵も)。しかし、私はこのタスクを達成するのに少し苦労しています。
WIN32 呼び出しを指す Web サイトをいくつか見つけました。Windows XP でコードを実行すると、証明書は個人証明書に保存され、問題なくエクスポートできます。このコードを Windows 7 64 ビットで実行すると、証明書はエラーなしで取得されますが、証明書はエクスポートできません。その後、証明書を割り当てている Web サイトで使用できません。
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#