2012-06-29 2 views
1

Я пытаюсь создать самоподписанный сертификат на компьютерах Windows. Я хочу, чтобы сертификат можно было экспортировать (даже частные ключи). Тем не менее, мне трудно справиться с этой задачей.Создать самоподписанный сертификат, который можно экспортировать

Я нашел несколько веб-сайтов, которые указывают на вызовы WIN32. Когда я запускаю код в Windows XP, сертификат хранится в личных сертификатах и ​​может быть экспортирован в порядке. Когда я запускаю этот код на 64-разрядной версии Windows 7, я получаю сертификат без ошибок, но сертификат не экспортируется. Я не могу использовать его для веб-сайта, на который я присваиваю сертификат.

 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, чтобы указать на этот сертификат.

Смежные вопросы