2012-06-29 39 views
1

我正試圖在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(); 

請注意證書類是一個內部類,它只是圍繞我使用的不同靜態方法和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#

回答

3

我發現導致我無法導出證書的問題。事實證明,我實際上並不能將它導出到Windows XP上(我已經看過幾次,但那是在我調試時,並且之後沒有執行代碼導致它中斷)。

在清理程序,按鍵是越來越刪除:

NativeMethods.CryptAcquireContextW(
    out providerContext, 
    containerName, 
    null, 
    1, // PROV_RSA_FULL 
    0x10); // CRYPT_DELETEKEYSET 

這將導致該證書不再能夠導出私鑰。當該行被註釋掉時,證書已安裝在本地計算機的個人證書存儲區中。它也被允許導出,因此允許我將IIS配置爲指向此證書。