Как можно создать X509Certificate2 из байтового массива PKCS # 12 и вызвать CryptographicException («Система не может найти указанный файл.»)? - PullRequest
34 голосов
/ 30 сентября 2010

Я пытаюсь создать X509Certificate2 из BLOB-объекта PKCS # 12 в байтовом массиве и получаю довольно загадочную ошибку. Этот код выполняется в настольном приложении с правами администратора в Windows XP.

Трассировка стека выглядит следующим образом, но я заблудился, пытаясь устранить неполадки, потому что _LoadCertFromBlob помечен [MethodImpl(MethodImplOptions.InternalCall)].

System.Security.Cryptography.CryptographicException: The system cannot find the file specified.
  at System.Security.Cryptography.CryptographicException.ThrowCryptogaphicException(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)
  at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(Byte[] rawData, String password, X509KeyStorageFlags keyStorageFlags)

РЕДАКТИРОВАТЬ: BLOB-объект представляет собой настоящий PKCS # 12, сгенерированный BouncyCastle для C # , содержащий закрытый ключ RSA и сертификат (либо самоподписанный, либо недавно зарегистрированный в СА) - - я пытаюсь преобразовать закрытый ключ и сертификат из библиотеки BouncyCastle в библиотеку System.Security.Cryptography путем экспорта из одного и импорта в другой. Этот код работает на подавляющем большинстве систем, в которых он был опробован; Я просто никогда не видел той конкретной ошибки, сгенерированной этим конструктором. На этой коробке может быть какая-то странная странность.

РЕДАКТИРОВАТЬ 2: Ошибка происходит в другой среде в другом городе, и я не могу воспроизвести ее локально, поэтому мне может понадобиться записать ее на мелкую версию XP .

Так как вы спросили, вот фрагмент, о котором идет речь. Код принимает закрытый ключ и сертификат в представлении BouncyCastle, удаляет все предыдущие сертификаты для того же Отличительного имени из хранилища личных ключей и импортирует новый закрытый ключ и сертификат в хранилище личных ключей через промежуточный BLOB-объект PKCS # 12.

// open the personal keystore
var msMyStore = new X509Store(StoreName.My);
msMyStore.Open(OpenFlags.MaxAllowed);

// remove any certs previously issued for the same DN
var oldCerts =
    msMyStore.Certificates.Cast<X509Certificate2>()
        .Where(c => X509Name
                        .GetInstance(Asn1Object.FromByteArray(c.SubjectName.RawData))
                        .Equivalent(CurrentCertificate.SubjectDN))
        .ToArray();
if (oldCerts.Length > 0) msMyStore.RemoveRange(new X509Certificate2Collection(oldCerts));

// build a PKCS#12 blob from the private key and certificate
var pkcs12store = new Pkcs12StoreBuilder().Build();
pkcs12store.SetKeyEntry(_Pkcs12KeyName,
                        new AsymmetricKeyEntry(KeyPair.Private),
                        new[] {new X509CertificateEntry(CurrentCertificate)});
var pkcs12data = new MemoryStream();
pkcs12store.Save(pkcs12data, _Pkcs12Password.ToCharArray(), Random);

// and import it.  this constructor call blows up
_MyCertificate2 = new X509Certificate2(pkcs12data.ToArray(),
                                       _Pkcs12Password,
                                       X509KeyStorageFlags.Exportable);
msMyStore.Add(_MyCertificate2);
msMyStore.Close();

Ответы [ 5 ]

40 голосов
/ 30 сентября 2010

У вас есть PKCS # 12 или просто PFX-файл? В мире Microsoft то же самое, но другие думают иначе (см. http://www.drh -consultancy.demon.co.uk / pkcs12faq-old.html # PFX ).

Вы можете попробовать просто следовать

X509Certificate2 cert = X509Certificate2(byte[] rawData, "password");
X509Certificate2 cert2 = X509Certificate2(byte[] rawData, "password",
              X509KeyStorageFlags.MachineKeySet |
              X509KeyStorageFlags.PersistKeySet |
              X509KeyStorageFlags.Exportable);

(см. http://msdn.microsoft.com/en-us/library/ms148418.aspx) или

X509Certificate2 cert = X509Certificate2("C:\Path\my.pfx", "password");

(см. http://msdn.microsoft.com/en-us/library/ms148420.aspx и http://msdn.microsoft.com/en-us/library/ms148442.aspx, если вам нужно использовать некоторые флаги)

ОБНОВЛЕНО : Было бы полезно, если вы вставили фрагмент кода, а не только трассировку стека исключений.

Какой X509KeyStorageFlags вы используете? Вы можете использовать Process Monitor , чтобы узнать, какой файл не может найти конструктор X509Certificate2. Это может быть, например, отсутствие контейнера ключей по умолчанию для текущего пользователя в Windows XP, в котором возникла проблема. Вы можете создать его и повторить импорт.

9 голосов
/ 16 августа 2014

Я столкнулся с той же проблемой.

В соответствии с этой статьей kb проблема заключалась в том, что конструктор пытается загрузить сертификат в профиль текущего пользователя, но в коде .Net я выдавал себя за пользователя и поэтому он не загружался.профиль пользователя.Конструктор требует, чтобы загруженный профиль пользователя работал правильно.

Из статьи:

Конструкторы класса X509Certificate2 пытаются импортировать сертификат в профиль пользователя учетной записи пользователя, которую приложениеработает. Много раз приложения ASP.NET и COM + олицетворяют клиентов.Когда они это делают, они не загружают профили пользователей для олицетворенного пользователя по соображениям производительности.Таким образом, они не могут получить доступ к хранилищу сертификатов «Пользователь» для олицетворенного пользователя.

При загрузке профиля пользователя исправлена ​​ошибка.

4 голосов
/ 19 марта 2016

Запуская это в веб-приложении в Windows 2012, установите для параметра пула приложений Load User Profile значение true, чтобы оно заработало.

Для этого запустите inetmgr.exe, перейдите к Advanced Settings для нужного пула приложений, измените Load User Profile в Process Model на true.

2 голосов
/ 06 марта 2017

У меня была такая же проблема.

  1. Откройте IIS на сервере, на котором размещен сайт.
  2. Найти пул приложений для сайта.
  3. Нажмите Расширенные настройки.
  4. Измените «Загрузить профиль пользователя» на true. (может потребоваться перезагрузка или перезагрузка)

Это позволяет криптосистеме работать.

enter image description here

1 голос
/ 16 октября 2011

У меня была точно такая же проблема. Тот же код и данные / сертификаты отлично работали в Windows 2003 x86 при запуске под определенным пользователем, но не работали под другой учетной записью (которая также использовалась для запуска пулов приложений IIS).

Очевидно, что другие вещи исчерпали ресурсы в Windows, так что отказавший пользователь не мог действительно загрузить профиль пользователя (его рабочий стол был странным), хотя в Event Viewer не было связанных событий *1004*.

Перезагрузка временно решила проблему. Хотя это не является постоянным решением проблемы, оно показывает, что есть что-то еще (например, компоненты COM +, службы собственного кода и т. Д.), Потребляющие ресурсы, которые необходимо исследовать. Это также показывает нестабильность платформ Windows ...

...