2009-01-08 11 views
26

Aquí está el código para agregar un pfx al almacén de certificados.Cómo establecer el permiso de lectura en el archivo de clave privada del certificado X.509 de .NET

X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine); 
store.Open(OpenFlags.ReadWrite); 
X509Certificate2 cert = new X509Certificate2("test.pfx", "password"); 
store.Add(cert); 
store.Close(); 

Sin embargo, no pude encontrar una manera de establecer el permiso para NetworkService para acceder a la clave privada.

¿Alguien puede arrojar algo de luz? Gracias por adelantado.

Respuesta

16

de hacerlo mediante programación, hay que hacer tres cosas:

  1. obtener la ruta de la carpeta de clave privada.

  2. Obtenga el nombre de archivo de la clave privada dentro de esa carpeta.

  3. Agregue el permiso a ese archivo.

Ver this post de un código de ejemplo que hace las tres cosas (ver específicamente el método "AddAccessToCertificate").

+0

Gracias, me gusta el proyecto de código uno. –

+0

¿Ha conseguido que esto funcione cuando usa el escritorio remoto? Puedo ver la clave cuando accedo pero en el momento en que mi programa termina, desaparece. –

11

Puede usar el WinHttpCertCfg.exe tool que se envía como parte del Windows Server 2003 Resource Kit Tools.

Ejemplo:

winhttpcertcfg -g -c LOCAL_MACHINE\My -s test -a NetworkService 


Como alternativa, se podría utilizar el Find Private Key tool que se incluye con el SDK de WCF, para encontrar la ubicación en el disco de archivo de la clave privada del certificado. Luego puede simplemente usar ACL para establecer los privilegios correctos en el archivo.

Ejemplo:

FindPrivateKey My LocalMachine -n "CN=test" 
+0

Gracias, winhttpcertcfg es una buena manera de hacerlo. –

40

Esta respuesta es tarde pero quería post-it para cualquier otra persona que viene a buscar aquí:

He encontrado un artículo en el blog de MSDN que dio una solución utilizando CryptoKeySecurity here, y aquí es un ejemplo de una solución de C#:

var rsa = certificate.PrivateKey as RSACryptoServiceProvider; 
if (rsa != null) 
{ 
    // Modifying the CryptoKeySecurity of a new CspParameters and then instantiating 
    // a new RSACryptoServiceProvider seems to be the trick to persist the access rule. 
    // cf. http://blogs.msdn.com/b/cagatay/archive/2009/02/08/removing-acls-from-csp-key-containers.aspx 
    var cspParams = new CspParameters(rsa.CspKeyContainerInfo.ProviderType, rsa.CspKeyContainerInfo.ProviderName, rsa.CspKeyContainerInfo.KeyContainerName) 
    { 
     Flags = CspProviderFlags.UseExistingKey | CspProviderFlags.UseMachineKeyStore, 
     CryptoKeySecurity = rsa.CspKeyContainerInfo.CryptoKeySecurity 
    }; 

    cspParams.CryptoKeySecurity.AddAccessRule(new CryptoKeyAccessRule(sid, CryptoKeyRights.GenericRead, AccessControlType.Allow)); 

    using (var rsa2 = new RSACryptoServiceProvider(cspParams)) 
    { 
     // Only created to persist the rule change in the CryptoKeySecurity 
    } 
} 

estoy usando un SecurityIdentifier para identificar la cuenta sino un NTAccount funcionaría igual de bien.

+2

Prefiero esta solución ya que hay menos código y no hay necesidad de meterse con las rutas de archivos. – Bronumski

+1

En mi caso, mi clave ya existía y quería volver a agregarla con los permisos. Esto falló silenciosamente porque el archivo de clave privada en 'C: \ ProgramData \ Microsoft \ Crypto \ RSA \ MachineKeys' se" separó "del certificado. La solución era crear el certificado con banderas como: 'X509Certificate2 cert = new X509Certificate2 (pathToCert," contraseña ", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);' Ver esto [respuesta] (http://stackoverflow.com/questions/ 3625624/inserting-certificate-with-privatekey-in-root-localmachine-certificate-store). – Mark

+1

Para algunos certificados, creo que aquellos hechos con proveedores de Crytography Next Gen (CNG), el código anterior no puede encontrar la clave privada. En ese caso, puede que esto ayude: https://stackoverflow.com/a/22146915 –

11

En caso de que esto ayuda a cualquier otra persona, me escribió la respuesta de Jim inundación en Powershell

function Set-PrivateKeyPermissions { 
param(
[Parameter(Mandatory=$true)][string]$thumbprint, 
[Parameter(Mandatory=$false)][string]$account = "NT AUTHORITY\NETWORK SERVICE" 
) 
#Open Certificate store and locate certificate based on provided thumbprint 
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store("My","LocalMachine") 
$store.Open("ReadWrite") 
$cert = $store.Certificates | where {$_.Thumbprint -eq $thumbprint} 

#Create new CSP object based on existing certificate provider and key name 
$csp = New-Object System.Security.Cryptography.CspParameters($cert.PrivateKey.CspKeyContainerInfo.ProviderType, $cert.PrivateKey.CspKeyContainerInfo.ProviderName, $cert.PrivateKey.CspKeyContainerInfo.KeyContainerName) 

# Set flags and key security based on existing cert 
$csp.Flags = "UseExistingKey","UseMachineKeyStore" 
$csp.CryptoKeySecurity = $cert.PrivateKey.CspKeyContainerInfo.CryptoKeySecurity 
$csp.KeyNumber = $cert.PrivateKey.CspKeyContainerInfo.KeyNumber 

# Create new access rule - could use parameters for permissions, but I only needed GenericRead 
$access = New-Object System.Security.AccessControl.CryptoKeyAccessRule($account,"GenericRead","Allow") 
# Add access rule to CSP object 
$csp.CryptoKeySecurity.AddAccessRule($access) 

#Create new CryptoServiceProvider object which updates Key with CSP information created/modified above 
$rsa2 = New-Object System.Security.Cryptography.RSACryptoServiceProvider($csp) 

#Close certificate store 
$store.Close() 

} 

Tenga en cuenta que el parámetro de la cuenta puede ser en forma de "dominio \ usuario", así (no sólo construida en nombres) - Probé esto en mi entorno y lo convirtió automáticamente al SID apropiado

Cuestiones relacionadas