2010-09-29 52 views
29

estoy tratando de construir un X509Certificate2 de una burbuja PKCS # 12 en una matriz de bytes y conseguir un error bastante desconcertante. Este código se ejecuta en una aplicación de escritorio con derechos de administrador en Windows XP.¿Cómo se puede construir un X509Certificate2 a partir de una matriz de bytes PKCS # 12 CryptographicException tirar ("el sistema no puede encontrar el archivo especificado.")?

El seguimiento de la pila es el siguiente, pero me perdí tratando de solucionarlo porque _LoadCertFromBlob está marcado [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: La gota es una verdadera PKCS # 12 generada por BouncyCastle for C# que contiene una clave privada RSA y un certificado (ya sea auto-firmado o recientemente inscrito con un CA) - lo que estoy tratando de hacer es convertir la clave privada y el certificado de la biblioteca BouncyCastle a la biblioteca System.Security.Cryptography exportando de uno e importando al otro. Este código funciona en la gran mayoría de los sistemas en los que se ha probado; Nunca he visto ese error en particular arrojado por ese constructor. Puede ser algún tipo de rareza ambiental en esa única caja.

EDIT 2: El error se produce en un entorno diferente en una ciudad diferente, y no puedo reproducirlo localmente, por lo que puede terminar teniendo que atribuirlo a una instalación de XP fallida.

Dado que usted pidió, sin embargo, aquí es el fragmento en cuestión. El código toma una clave privada y el certificado en representación BouncyCastle, se borran todos los certificados anteriores para el mismo nombre completo del almacén de claves personales, e importa la nueva clave privada y el certificado al almacén de claves personales a través de una mancha intermedia 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(); 

Respuesta

34

¿Tiene PKCS # 12 o PFX-file? En el mundo de Microsoft, es lo mismo, pero otros piensan en otro (ver http://www.drh-consultancy.demon.co.uk/pkcs12faq-old.html#PFX).

Usted puede tratar simplemente siguiendo

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

(ver http://msdn.microsoft.com/en-us/library/ms148418.aspx) o

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

(ver http://msdn.microsoft.com/en-us/library/ms148420.aspx y http://msdn.microsoft.com/en-us/library/ms148442.aspx si necesita usar algunas banderas)

ACTUALIZADO: sería ser útil si inserta un fragmento de código y no solo el seguimiento de pila de excepción.

Qué X509KeyStorageFlags se utilizan? Puede usar Process Monitor para averiguar qué archivo no pudo encontrar el constructor X509Certificate2. Puede ser, por ejemplo, que no hay un contenedor de clave predeterminado para el usuario actual en Windows XP que tiene el problema. Puede crearlo y reintentar la importación.

+3

Adición X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable para el constructor al cargar desde byte [] funcionó para mí. – Muxa

+2

Encontré este mismo error en Windows Server 2012, donde el mismo código no tenía problemas en Windows 7 o en la nube de Azure. Cambiar el indicador a MachineKeySet solucionó el problema. – RMD

+2

Tenga cuidado con el indicador PersistKetSet en este ejemplo: deja archivos clave en el disco que nunca se limpian. Si realiza esta llamada con mucha frecuencia, terminará con una gran tarea de limpieza. (Pregúnteme cómo lo sé). Si está utilizando el certificado solo en la memoria, simplemente especifique MachineKeySet. Si ha terminado con el certificado en memoria en el código, llame al método Restablecer para eliminar inmediatamente el archivo de clave. Sin embargo, es mejor agregar una vez en la tienda y volver a cargar. Para eso es para eso. –

1

que tenía exactamente el mismo problema. El mismo código y los mismos datos/cert se ejecutaron correctamente en Windows 2003 x86 cuando se ejecutaban bajo un usuario específico, pero fallaban en otra cuenta (que también se usaba para ejecutar pools de aplicaciones IIS).

Al parecer, alguna otra cosa agotado los recursos en Windows, por lo que el usuario no realmente no podía cargar el perfil del usuario (su escritorio era raro-mirando), aunque hubo hay eventos relacionados en el Visor de sucesos.

Un reinicio ha resuelto el problema temporalmente. Aunque esta no es una solución permanente al problema, muestra que hay algo más (por ejemplo, componentes COM +, servicios de código nativo, etc.) que consume recursos que deben investigarse. También muestra la inestabilidad de las plataformas de Windows ...

+0

Este sabor particular de inestabilidad parece estar relacionado con una combinación de software de escritorio dependiente de la comunicación entre procesos y poca solidez frente a los recursos agotamiento. He visto exactamente la misma clase de problemas con GNOME, y especialmente con Evolution, en Linux en el pasado. –

8

Me encontré con el mismo problema.

De acuerdo con este kb article el problema era que el constructor intenta cargar el certificado en el perfil del usuario actual, pero el código .Net estaba imitando al usuario y por lo tanto no había cargado el perfil del usuario. El constructor requiere que el perfil de usuario cargado funcione correctamente.

Desde el artículo:

Los constructores de clase X509Certificate2 intenta importar el certificado en el perfil de usuario de la cuenta de usuario que la aplicación se ejecuta en muchas ocasiones, ASP.NET y COM + aplicaciones suplantar clientes.. Cuando lo hacen, no cargan los perfiles de usuario para el usuario suplantado por motivos de rendimiento. Por lo tanto, no pueden acceder al almacén de certificados "Usuario" para el usuario suplantado.

Cargando el perfil de usuario se ha solucionado el error.

+0

La pieza de código en cuestión se ejecutaba dentro de una aplicación de escritorio, por lo que dudo que un perfil de usuario descargado estuviera en cuestión. –

+0

@Zain, gracias por la respuesta. ¿Sabes también que esta es la mejor manera de solucionar este problema? Me hace considerar debido al impacto en el rendimiento. Thx – curiousBoy

+0

@ curiousBoy Como dije en la última línea de mi respuesta, haga una llamada de API para cargar el perfil de usuario. –

4

Al ejecutar esto en una aplicación web en Windows 2012, establecer la opción del grupo de aplicaciones Load User Profile en true lo hizo funcionar.

Para ello, ejecute inetmgr.exe, ir a Advanced Settings para el grupo de aplicaciones correcto, cambiar Load User Profile bajo Process Model true.

+0

Esto sucedió en una aplicación de escritorio, no en una aplicación o servicio web. –

1

Tuve este mismo problema.

  1. Abra IIS en el servidor que aloja el sitio.
  2. Encuentra el grupo de aplicaciones para el sitio.
  3. Haga clic en Configuración avanzada.
  4. Cambie "Cargar perfil de usuario" a verdadero. (puede ser necesario reiniciar o reiniciar)

Esto permite que el crypto subsystem funcione.

enter image description here

+1

Esta es la cuarta respuesta que apunta a problemas con los grupos de aplicaciones de IIS. Tuve este problema en una aplicación de escritorio. Es completamente posible que el perfil del usuario se haya dañado de alguna manera, pero definitivamente se cargó. –

+0

Interesante, no es obvio por su pregunta que es una aplicación de escritorio. Esta solución funcionó para mí en mi aplicación IdentityServer3 MVC. El proyecto funcionaba bien a nivel local, pero tan pronto como llegaba al servidor se bloqueaba. Esta bandera fue la única solución. ¿Permisos quizás en la aplicación de escritorio? – paqogomez

+0

Se ejecutó en una cuenta de grupo de administrador en una máquina con XP, por lo que ni los permisos ni el UAC deberían haber estado en cuestión. No pude reproducirlo en ninguna otra máquina, así que mi mejor conjetura en este punto es un perfil roto o una configuración de sistema operativo que no funciona. –

Cuestiones relacionadas