Исключение конструктора X509

//cert is an EF Entity and 
//    cert.CertificatePKCS12 is a byte[] with the certificate.

var certificate = new X509Certificate(cert.CertificatePKCS12, "SomePassword");

При загрузке сертификата из нашей базы данных на нашем промежуточном сервере (Windows 2008 R2/IIS7.5) мы получаем это исключение:

System.Security.Cryptography.CryptographicException: An internal error occurred.

   at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)
   at System.Security.Cryptography.X509Certificates.X509Utils._LoadCertFromBlob(Byte[] rawData, IntPtr password, UInt32 dwFlags, Boolean persistKeySet, SafeCertContextHandle& pCertCtx)
   at System.Security.Cryptography.X509Certificates.X509Certificate.LoadCertificateFromBlob(Byte[] rawData, Object password, X509KeyStorageFlags keyStorageFlags)

ПРИМЕЧАНИЕ. Эта проблема не происходит локально (Windows 7/Casini).

Любое понимание очень ценится.

Ответ 1

Включает параметр конфигурации пула приложений IIS (пулы приложений > Дополнительные параметры) для загрузки пользовательского профиля для пользователя идентификации пула приложений. Если установлено значение false, контейнеры ключей недоступны.

Так что просто установите Load User Profile как True

App Pool- > Экран дополнительных настроек

Ответ 2

Скорее всего, когда вы работаете с Visual Studio/Cassini, он обращается к вашему хранилищу сертификатов пользователя, даже если вы загружаете его из байтов. Не могли бы вы попробовать это и посмотреть, решит ли он вашу проблему:

var certificate = new X509Certificate(
    cert.CertificatePKCS12, "SomePassword", X509KeyStorageFlags.MachineKeySet);

Это приведет к тому, что IIS (который работает как пользователь ASP.NET, который, вероятно, не имеет доступа к хранилищу пользователей), использует хранилище устройств.

Эта страница объясняет конструктор более подробно, и this страница объясняет перечисление X509KeyStorageFlags.

Edit: Основываясь на второй ссылке от cyphr, похоже, что это может быть хорошей идеей (если предыдущее решение не работает), чтобы объединить некоторые из значений перечисления FlagsAttribute следующим образом:

var certificate = new X509Certificate(
    cert.CertificatePKCS12, "SomePassword",
    X509KeyStorageFlags.MachineKeySet
    | X509KeyStorageFlags.PersistKeySet
    | X509KeyStorageFlags.Exportable);

Кроме того, если у вас есть доступ, вы можете попробовать изменить параметр пула приложений, чтобы использовать LocalService (а затем перезапустить AppPool). Это может повысить ваши права на соответствующий уровень, если это проблема.

Наконец, вы можете использовать File.WriteAllBytes, чтобы записать содержимое CertificatePKCS12 в файл pfx и посмотреть, можно ли вручную импортировать он использует консоль сертификатов в MMC (вы можете удалить после успешного импорта, это просто проверить). Возможно, ваши данные забиты, или пароль неверен.

Ответ 3

Используйте этот код:

certificate = new X509Certificate2(System.IO.File.ReadAllBytes(p12File)
                                   , p12FilePassword
                                   , X509KeyStorageFlags.MachineKeySet |
                                     X509KeyStorageFlags.PersistKeySet | 
                                     X509KeyStorageFlags.Exportable);

Ответ 4

У меня были проблемы с Windows 2012 Server R2, где мое приложение не могло загружать сертификаты для PFX на диск. Все будет нормально работать с моим приложением в качестве администратора, а исключение - "Отказано в доступе", поэтому это должно быть проблема с правами доступа. Я пробовал некоторые из вышеупомянутых советов, но у меня все еще была проблема. Я обнаружил, что указание следующих флагов в качестве третьего параметра конструктора cert сделало для меня трюк:

 X509KeyStorageFlags.UserKeySet | 
 X509KeyStorageFlags.PersistKeySet | 
 X509KeyStorageFlags.Exportable

Ответ 5

Чтобы действительно решить вашу проблему, а не просто догадываться, что это может быть, нужно иметь возможность воспроизвести вашу проблему. Если вы не можете предоставить тестовый файл PFX, который имеет такую ​​же проблему, вы должны сами изучить проблему. Первым важным вопросом является: возникновение исключения "Внутренняя ошибка произошла" в частной ключевой части PKCS12 или в публичной части самого сертификата?

Поэтому я бы рекомендовал вам попробовать повторить тот же эксперимент с тем же сертификатом, экспортированный без закрытого ключа (например, файл .CER):

var certificate = new X509Certificate(cert.CertificateCER);

или

var certificate = new X509Certificate.CreateFromCertFile("My.cer");

Это может помочь проверить, является ли происхождение вашей проблемы закрытым ключом или некоторыми свойствами сертификата.

Если у вас возникнут проблемы с файлом CER, вы можете безопасно разместить ссылку на файл, потому что он имеет только общедоступную информацию. В качестве альтернативы вы можете выполнить хотя бы

CertUtil.exe -dump -v "My.cer"

или

CertUtil.exe -dump -v -privatekey -p SomePassword "My.pfx"

(вы также можете использовать некоторые другие параметры) и опубликовать некоторые части для вывода (например, свойства закрытого ключа без самого PRIVATEKEYBLOB).

Ответ 7

Вам необходимо импортировать сертификат .cer в локальное хранилище ключей. Нет необходимости импортировать ваш сертификат .p12 - вместо этого используйте второй сертификат, который выдает на ваш аккаунт Apple. Я думаю, что это должна быть действительная пара сертификатов (одна в файловой системе, вторая в хранилище ключей). Вы должны будете установить все 3 флага в dll, конечно.