web-dev-qa-db-fra.com

Comment la construction d'un X509Certificate2 à partir d'un tableau PKCS # 12 octets peut-elle lever CryptographicException ("Le système ne peut pas trouver le fichier spécifié.")?

J'essaie de construire un X509Certificate2 À partir d'un blob PKCS # 12 dans un tableau d'octets et d'obtenir une erreur plutôt déroutante. Ce code s'exécute dans une application de bureau avec des droits d'administrateur sur Windows XP.

La trace de la pile est la suivante, mais je me suis perdu en essayant de dépanner car _LoadCertFromBlob Est marqué [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)

EDIT: Le blob est un vrai PKCS # 12 généré par BouncyCastle for C # contenant une clé privée RSA et un certificat (soit auto -signé ou récemment inscrit auprès d'une autorité de certification) - ce que j'essaie de faire est de convertir la clé privée et le certificat de la bibliothèque BouncyCastle en bibliothèque System.Security.Cryptography en exportant de l'un et en important dans l'autre. Ce code fonctionne sur la grande majorité des systèmes sur lesquels il a été essayé; Je n'ai jamais vu cette erreur particulière lancée par ce constructeur. Cela peut être une sorte de bizarrerie environnementale sur cette seule boîte.

EDIT 2: L'erreur se produit dans un environnement différent dans une ville différente, et je ne peux pas le reproduire localement, donc je pourrais finir par avoir à la craie jusqu'à une installation cassée XP.

Depuis que vous avez posé la question, voici le fragment en question. Le code prend une clé privée et un certificat dans la représentation BouncyCastle, supprime tous les certificats précédents pour le même nom distinctif du magasin de clés personnelles et importe la nouvelle clé privée et le nouveau certificat dans le magasin de clés personnelles via un blob PKCS # 12 intermédiaire.

// 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();
37
Jeffrey Hantin

Avez-vous PKCS # 12 ou simplement un fichier PFX? Dans le monde Microsoft, c'est la même chose, mais d'autres en pensent un autre (voir http://www.drh-consultancy.demon.co.uk/pkcs12faq-old.html#PFX ).

Vous pouvez essayer de suivre

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

(voir http://msdn.Microsoft.com/en-us/library/ms148418.aspx ) ou

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

(voir http://msdn.Microsoft.com/en-us/library/ms148420.aspx et http://msdn.Microsoft.com/en-us/library/ms148442 .aspx si vous avez besoin d'utiliser des drapeaux)

[~ # ~] mis à jour [~ # ~] : il serait utile d'insérer un fragment de code et pas seulement la trace de la pile d'exceptions.

Lequel X509KeyStorageFlags utilises tu? Vous pouvez utiliser Process Monitor pour savoir quel fichier n'a pas pu trouver le X509Certificate2 constructeur. Il se peut par exemple qu'il n'y ait pas de conteneur de clés par défaut pour l'utilisateur actuel sous Windows XP ayant le problème. Vous pouvez le créer et réessayer l'importation.

43
Oleg

Je suis tombé sur le même problème.

Selon cela kb article le problème était que le constructeur essayait de charger le certificat dans le profil de l'utilisateur actuel, mais le code .Net J'usurpais l'identité de l'utilisateur et il n'avait donc pas chargé le profil utilisateur. Le constructeur requiert que le profil utilisateur chargé fonctionne correctement.

De l'article:

Les constructeurs de classe X509Certificate2 tentent d'importer le certificat dans le profil utilisateur du compte d'utilisateur dans lequel l'application s'exécute. Plusieurs fois, les applications ASP.NET et COM + empruntent l'identité des clients. Lorsqu'ils le font, ils ne chargent pas les profils utilisateur pour l'utilisateur emprunté pour des raisons de performances. Par conséquent, ils ne peuvent pas accéder au magasin de certificats "Utilisateur" pour l'utilisateur emprunté.

Le chargement du profil utilisateur a corrigé l'erreur.

10
Zain Rizvi

En cours d'exécution dans une application Web sous Windows 2012, Définition de l'option de pool d'applications Load User Profile à vrai fait fonctionner.

Pour ce faire, exécutez inetmgr.exe, aller à Advanced Settings pour le pool d'applications approprié, modifiez Load User Profile sous Process Model à vrai.

4
deerchao

J'ai eu le même problème.

  1. Ouvrez IIS sur le serveur hébergeant le site.
  2. Recherchez le pool d'applications pour le site.
  3. Cliquez sur Paramètres avancés.
  4. Remplacez "Charger le profil utilisateur" par true. (peut nécessiter un redémarrage ou un redémarrage)

Cela permet au sous-système de cryptographie de fonctionner.

enter image description here

3
paqogomez

J'ai eu exactement le même problème. Le même code et les mêmes données/certificats ont bien fonctionné sur Windows 2003 x86 lors de l'exécution sous un utilisateur spécifique, mais ont échoué sous un autre compte (qui a également été utilisé pour exécuter IIS pools d'applications).

Apparemment, une autre chose a épuisé les ressources sous Windows, de sorte que l'utilisateur défaillant ne pouvait pas vraiment charger le profil de l'utilisateur (son bureau était bizarre), bien qu'il y ait aucun événement connexe dans l'Observateur d'événements.

Un redémarrage a résolu le problème temporairement. Bien que ce ne soit pas une solution permanente au problème, cela montre qu'il y a autre chose (par exemple, des composants COM +, des services de code natif, etc.) consommant des ressources qui doit être étudié. Il montre également l'instabilité des plateformes Windows ...

1
Ricardo Pardini