Pregunta

Tengo problemas para insertar un nuevo certificado de CA con PrivateKey en el almacén de certificados raíz de LocalMachine.

Esto es lo que pasa:

//This doesn't help either.
new StorePermission (PermissionState.Unrestricted) { Flags = StorePermissionFlags.AddToStore }.Assert();
var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
privkey.PersistKeyInCsp = true;
//This shouldn't be necessary doesn't make a difference what so ever.
RSACryptoServiceProvider.UseMachineKeyStore = true;
cert.PrivateKey = privkey;
store.Open (OpenFlags.MaxAllowed);
store.Add (cert);
store.Close ();

El certificado se inserta y todo se ve elegante: (¡ver!) note it says it has a private key

NOTA: IS dice que tiene una tecla privada.

Entonces dirías que uno podría encontrarlo con Findprivatekey

C:\Users\Administrator\Desktop>FindPrivateKey.exe Root LocalMachine -t "54 11 b1 f4 31 99 19 d3 5a f0 5f 01 95 fc aa 6f 71 12 13 eb"
FindPrivateKey failed for the following reason:
Unable to obtain private key file name

Use /? option for help 

Es lindo ... ¡pero está mal! (Referencia de 2 perros estúpidos)

Y el diálogo de exportación de certificado me da este mensaje muy bueno:alt text

Este código se ejecuta mientras se hace pasar por un administrador usando este fragmento: haga clic aquí

¿Me encantaría saber por qué?

(Probado en Windows Server 2008 R2 y Windows 7)

¡Voy a ser condenado!

Funciona cuando lo compilo en v3.5 !!!!

¿Qué hacer?

¿Fue útil?

Solución

Tenía exactamente el mismo problema y la solución resultó ser realmente simple. Todo lo que tenía que hacer era pasar

X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet

a CTOR de X509Certificate2. Ahora está utilizando las dotnetutilidades para convertir el certificado BouncyCastle en el .NET One, pero el método Helper crea el certificado .NET con el valor predeterminado (en lugar de KachineKeySet + PersistKeySet).

Y organizar la clave privada como esta:

var cspParams = new CspParameters
{
      KeyContainerName = Guid.NewGuid().ToString(),
      KeyNumber = (int)KeyNumber.Exchange,
      Flags = CspProviderFlags.UseMachineKeyStore
};

var rsaProvider = new RSACryptoServiceProvider(cspParams);

Espero que esto ayude.

Otros consejos

Me parece que deberías importar la llave de otra manera. Ver http://support.microsoft.com/kb/950090 para un ejemplo.

Además, no encuentro bueno para ahorrar una llave privada en UseMachineKeyStore. En la mayoría de los casos, necesita un certificado de importación con la clave privada en mi tienda de algún usuario e importar en el certificado Root Only sin clave privada.

Es necesario guardar la clave privada en la tienda de teclas de la máquina, que al menos debe proteger la clave para leer solo para algunos usuarios seleccionados y no para todos. El contenedor clave es solo un archivo en el sistema de archivos (consulte los archivos en el directorio "%AllUsersProfile% Microsoft Crypto Keys") que tiene descriptores de seguridad como otros archivos en NTFS. Para cambiar los descriptores de seguridad de los archivos que puede usar CspKeyContainerInfo.CryptoKeySecurity propiedad y AddAccessRule, RemoveAccessRule y así.

ACTUALIZADO: En primer lugar, lo siento por la larga respuesta.

Podría dividir Su código de programa en dos partes. En la primera parte, genera un certificado autofirmado que puede usarse como certificados de CA y lo guarda como rootcert.pfx expediente. En la segunda parte, importe el certificado, pero usa RSACryptoServiceProvider lleno de propiedades de la clave creada anterior en lugar de usar rootcert.pfx.

Sugiero reemplazar la segunda parte de su código a un código más estándar y simple: importar certificado con la clave privada desde rootcert.pfx Como se describe en http://support.microsoft.com/kb/950090. Funciona muy bien.

No me uso el Bouncycastle, por lo que no pude comentar la primera parte de su código, pero en general lo que hace en el código podría hacer también con respecto a Makecert.exe Utilidad del SDK de Windows. Puedes hacer como seguir

MakeCert.exe -pe -ss MY -a sha1 -cy authority -len 2048 -m 120 -r -# 1
             -n "CN=Some Root CA, C=NL, OU=BleedingEdge, ST=Somewhere, L=Somelane"

Luego, puede exportar certificado con o sin clave privada con respecto al Snap-in de certificado (para MMC.EXE). En el ejemplo anterior, no restringo CA para un EKU especial, por lo que puede usarlo sin ninguna restricción, pero si necesita las restricciones, puede agregar parámetros adicionales a Makecert.exe. También puede usar makecert.exe para crear otro certificado que se firmen con el certificado de CA. Por lo tanto, puede hacer un PKI pequeño con respecto solo a Makecert.exe.

Me parece que crear el certificado es realmente una parte separada de su código. Su principal problema está en la segunda parte.

Si desea el certificado de importación de CA, debe tener en cuenta algunas cosas importantes:

  • Deberías importarlo en Root o AuthRoot en localMachine en cada (o muchas) computadora de su organización, pero debe importar el certificado sin la clave privada. Puedes hacer esto con respecto a seguir

Certmgr.exe -add -c ca.cer -s -r localmachine authroot

  • Debe importar CA CACE con llave privada en la computadora en una computadora y solo para el usuario que emitirá otros certificados (¿Quién firmará nuevos certificados con la clave privada de CA)? Un uso para importar el certificado en el Mi tienda de certificación de Usuario actual. Entonces el código de la computadora podría parecer

siguiendo:

// import PFX
X509Certificate2 cert = new X509Certificate2 (@"c:\Oleg\rootcert.pfx", "password",
    X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
// save certificate and private key
X509Store storeMy = new X509Store (StoreName.My, StoreLocation.CurrentUser);
storeMy.Open (OpenFlags.ReadWrite);
storeMy.Add (cert);

// get certificate without private key
// one can import certificate from rootcert.cer instead
byte[] certBlobWithoutPrivateKey = cert.Export (X509ContentType.Cert);
// save pure certificate in Root of the local machine
X509Certificate2 certWithoutPrivateKey = new X509Certificate2 (certBlobWithoutPrivateKey);
X509Store storeRoot = new X509Store (StoreName.Root, StoreLocation.LocalMachine);
storeRoot.Open (OpenFlags.ReadWrite);
storeRoot.Add (certWithoutPrivateKey);

El código funcionará si lo hace cambiar StoreName.My y StoreLocation.CurrentUser a otros valores, pero no te recomiendo que hagas esto.

En general, la importación de certificados en el código .NET parece un poco extraño y no muestra lo que se hará bajo el capó. Windows solo sabe Contenedores clave donde las claves privadas (para ser exactamente el par de claves) se guardarán con respecto a CSP y Tiendas certificadas donde se guardarán los certificados (ver http://msdn.microsoft.com/en-us/library/bb204781.aspx Acerca de la ubicación de la tienda). Para poder guardar información sobre el contenedor clave en el almacén de certificados, Microsoft introdujo así Certificado de propiedades extendidas. Si usa las propiedades de .NET de X509Certificate2 me gusta Thumbprint, FriendlyName, HasPrivateKey, Archived y así sucesivamente trabaja con las propiedades extendidas del certificado. Por lo tanto, le recomiendo que importe CA Certificado dos veces. Uno en Root o AuthRoot sin que ajuste CERT_KEY_PROV_INFO_PROP_ID Certificado de propiedades extendidas Y una vez más en My Tienda con la configuración de la información sobre el lugar del contenedor clave con la clave privada (CERT_KEY_PROV_INFO_PROP_ID). Además, puede considerar eliminar la clave privada directamente después del uso, importarla solo si realmente necesita usarla y no lo sostenga permanentemente. Todo esto es importante tener una mejor seguridad.

He encontrado este problema y parece que incluso el usuario con el que está ejecutando la herramienta FindprivateKey no tiene acceso a la clave y, por lo tanto, obtendrá el mensaje "No se puede obtener el mensaje de nombre de archivo de clave privada". Puede ejecutar la herramienta como proceso LocalSystem.

Más información aquí:

http://www.itsolutionbraindumps.com/2011/02/finding-private-key-for-your.html

Dinko

nuevo x509Certificate2 (localpfxpath, inputPass, x509KeyStorageFlags.MachineKeySet & X509KeyStorageFlags.persistKeySet); con el & en lugar del | trabajó para mi.

Por lo general, los certificados en root no tendrán una clave privada para administrar. Debe importar a mi carpeta si está asociando la clave en la solicitud web. Tengo una excepción TLS/SSL donde tengo una cadena de certificados del cliente. Si almacena toda la cadena de certificados en mi tienda, me deshice de esa excepción. Donde el problema está con las cuentas de usuario. Utilidad para almacenar los certificados utiliza la cuenta de usuario actual y la aplicación real se ejecuta en la cuenta del sistema.

El problema básico es que la API de certificados .NET es solo un contenedor alrededor de la API de administrador de certificados C ++ ADVAPI32, por lo que no puede especificar todas las opciones que se pasan a esta API que realmente es responsable de pegar el certificado en Windows tienda de certificaciones y persistiendo las llaves. La conclusión es que el "UsemachinestoreLa opción debe pasar al Cspproviderflags que a su vez se pasa al Capi.crypt_machine_keyset. Este es el pequeño que determina si la clave se persiste de verdad o no. Parece que hay varias razones diferentes por las cuales esta opción no se establece a pesar de que establece el X509KeyStorageFlags.PersistKeySet y Kachekeyset y Exportable. Todas estas opciones solo viven siempre que la estúpida clave permanezca en la carpeta C: ProgramData Microsoft Crypto rsa KachineKeys . Si Crypt_Machine_KeySet no se establece al momento de la importación, Advapi32 quita la clave tan pronto como GC se elimina el mango del certificado.

Solución: Agregue el certificado a la raíz de confianza antes de importar el certificado a la tienda de la máquina personal. Al leer los registros de CAPI2, En realidad veo dos llamadas a "objetos X509" cada vez que el certificado se "importa". Uno siempre tiene el <Flags value="20" CRYPT_MACHINE_KEYSET="true"/>, (lo que queremos) pero el otro no a menos que "verifique la política de cadena" no devuelva errores. Entonces parece advapi32 está comprobando la "validez" del certificador y devuelve una excepción que es tragada por X509Certificate2 (Me encanta la cantidad de bloques de captura vacíos que tienen en ese código.) o advapi32 simplemente decide unilateralmente no persistir las claves de los certificados no confiables. (Por cierto, sospecho que este es un cambio de comportamiento entre 2008 y 20012, pero no he demostrado eso). Para trabajar en torno a esto, agregué un IF-Check a mi código para agregar el certificado de que si el emisor es igual al Sujeto (es un certificado autofirmado) luego agregue el certificado a la raíz antes de agregarlo a mi.

    if (certificate.Issuer.Equals(certificate.Subject))
    {
        using (X509Store store = new X509Store(StoreName.Root, StoreLocation.LocalMachine)) { 
            store.Open(OpenFlags.ReadWrite);
            store.Add(certificate);
            store.Close();
        }
    }

    using (X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine)){ 
        store.Open(OpenFlags.ReadWrite);
        store.Add(certificate);
        store.Close();
    }

NOTA: He descubierto que esto no es necésico si se usa un certificado que no ya tiene un identificador de clave de asunto. De alguna manera, cuando activas la API para generar el esquí en lugar de entregarlo, desencadena el condicional para pasar la bandera Magic Crypt_Machine_KeySet a Advapi32.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top