2012-05-07 14 views
19

Estoy intentando firmar un archivo con ECDSA utilizando la API de CNG y un certificado de la Tienda de certificados de Microsoft. He leído mucha documentación y casi terminado, pero me obsesiono con la importación de la clave privada del certificado. He hecho lo mismo con RSA, pero parece que se hace de manera muy diferente. Aquí está el código que tengo hasta ahora:Archivo de firma ECDSA con clave de la tienda C# .Net CNG

static void signFile() 
    { 
     X509Certificate2 myCert = 
      selectCert(StoreName.My, 
         StoreLocation.CurrentUser, 
         "Select a Certificate", 
         "Please select a certificate from the list below:"); 

     Console.Write("Path for file to sign: "); 
     string path = Console.ReadLine(); 
     TextReader file = null; 
     try 
     { 
      file = new StreamReader(path); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.Message); 
      Console.Write("\nPress any key to return to the main menu: "); 
      Console.ReadKey(); 
     } 
     UnicodeEncoding encoding = new UnicodeEncoding(); 
     byte[] data = encoding.GetBytes(file.ReadToEnd()); 
     ECDsaCng dsa = new ECDsaCng(
      CngKey.Import(StringToByteArray(myCert.PrivateKey.ToString()), 
          CngKeyBlobFormat.EccPrivateBlob, 
          CngProvider.MicrosoftSoftwareKeyStorageProvider)); 

     dsa.HashAlgorithm = CngAlgorithm.Sha384; 
     byte[] sig = dsa.SignData(data); 
     TextWriter signatureFile = new StreamWriter("signature.txt"); 
     signatureFile.WriteLine("-----BEGIN SHA384 SIGNATURE-----" + 
           ByteArrayToString(sig) + 
           "-----END SHA384 SIGNATURE-----"); 
     signatureFile.Close(); 
    } 

Y me sale el error

System.NotSupportedException: No se admite el algoritmo de clave del certificado.

Mi certificado es ECDSA_P256 sha384ECDSA con las siguientes extensiones:

Digital Signature, Non-repudiation, independent signing revocation list (CRL), CRL Signing (CRL) (c2) 
Server Authentication (1.3.6.1.5.5.7.3.1) 
Client Authentication (1.3.6.1.5.5.7.3.2) 
Code Signing (1.3.6.1.5.5.7.3.3) 
Unknown Key Usage (1.3.6.1.4.1.311.2.1.22) 
Unknown Key Usage (1.3.6.1.4.1.311.2.1.21) 
IKE-intermediary IP-security (1.3.6.1.5.5.8.2.2) 

Parecería como si el certificado era el problema, pero no estoy seguro de si podría ser el código o no.


Aquí está mi certificado con la clave pública:

Certificate: 
Data: 
    Version: 3 (0x2) 
    Serial Number: 2 (0x2) 
Signature Algorithm: ecdsa-with-SHA384 
    Issuer: C=##, O=#######, OU=#####, OU=#####, CN=########### 
    Validity 
     Not Before: Apr 27 16:35:51 2012 GMT 
     Not After : Apr 26 16:35:51 2017 GMT 
    Subject: C=##, O=###########, OU=#####, CN=############# 
    Subject Public Key Info: 
     Public Key Algorithm: id-ecPublicKey 
      Public-Key: (256 bit) 
      pub: 
       04:fc:d5:ce:ad:1f:0c:19:b9:3d:2b:bd:7d:f0:8c: 
       44:46:db:e3:42:14:b1:1a:9f:7c:ab:e1:be:ad:a5: 
       0c:03:2d:0f:ff:3f:10:d4:69:eb:4c:82:a1:2a:61: 
       56:45:03:04:a6:49:f7:16:6e:dd:60:22:c6:20:c5: 
       4d:44:49:21:41 
      ASN1 OID: prime256v1 
    X509v3 extensions: 
     X509v3 Key Usage: critical 
      Digital Signature, Non Repudiation, CRL Sign 
     X509v3 Extended Key Usage: critical 
      TLS Web Server Authentication, TLS Web Client Authentication, Co 
de Signing, Microsoft Commercial Code Signing, Microsoft Individual Code Signing 
, 1.3.6.1.5.5.8.2.2 
     X509v3 Authority Key Identifier: 
      DirName:/C=##/O=#######/OU=#####/OU=#####/CN=###### 
      serial:01 
     X509v3 Subject Key Identifier: 
      B7:A8:F9:55:9A:43:9E:BE:1C:4B:62:52:91:C2:F1:39:72:E1:CE:1B 
     X509v3 Basic Constraints: critical 
      CA:FALSE 
Signature Algorithm: ecdsa-with-SHA384 
    30:81:88:02:42:01:75:55:f3:64:f9:aa:2a:66:55:b1:ca:dc: 
    86:ac:1f:7d:2a:ec:10:87:db:74:88:0e:77:e3:18:82:15:a7: 
    32:91:1a:2d:ea:07:2e:78:8d:dc:8a:18:3c:2b:5a:9b:6a:0f: 
    97:f6:f8:8d:c5:fc:0e:9f:20:e9:b0:16:90:1a:c4:58:ac:02: 
    42:01:dc:b3:88:ae:44:54:c4:e0:b7:c2:37:88:0b:19:6b:96: 
    99:f7:21:12:45:12:21:e5:ab:83:39:a6:47:3a:08:87:b0:fa: 
    0e:31:1b:97:83:8d:65:30:a1:43:c1:82:27:77:6e:93:89:1b: 
    bd:57:b1:7a:54:9e:cc:e1:44:cc:74:16:c5 
+0

Microsoft tiene bastante limitado el soporte de criptografía de curva elíptica (ECC). Solo proporciona "curva elíptica DSA (ECDSA) sobre las curvas primarias estándar NIST P-256, P-384 y P-521". y esas deberían ser curvas "nombradas". ¿Sabes qué parámetros de dominio de EC están en el certificado? Alternativamente, puede pegar el texto hexadecimal, base64 o ASN.1 del certificado para que podamos averiguarlo. –

+0

Puede editar su pregunta en lugar de responder para proporcionar más información. Al volver a leer la pregunta, un certificado en sí mismo no contiene la clave privada. En general, usted crea un par de claves, crea una solicitud de certificado que contiene la clave pública y lo firma con la clave privada. Luego, la CA elabora un certificado y lo envía de regreso. Ese certificado solo contiene la clave pública. Entonces, cuando intenta importar la clave privada, ¿en qué formato es? PKCS # 12? Eso sería extensiones de archivo '.pkf' o' .p12'. –

+0

Ah, veo dónde te equivocas, debería haberme puesto las gafas. ToString no codifica la clave privada. Simplemente imprime algo de información en la clave privada. Puede usar el 'DSACryptoServiceProvider' que la propiedad PrivateKey realmente extiende en lugar de codificar/volver a codificar la clave privada. –

Respuesta

2

Si está ejecutando Windows Vista o Windows 2008, el CngKeyBlobFormat.EccPrivateBlob no es compatible. ¿Qué sistema operativo estás usando? CngKey.Import throws CryptographicException only on some machines

+1

Estaba usando Windows 7 pero ahora me he "actualizado" a 8. –

+0

Ok, puede ignorar mi respuesta, ya que ese problema no ocurrirá en Windows 7 y, presumiblemente, tampoco en Windows 8. – Anssssss

5

He estado luchando ECDsa y CngKey con certificados X509 durante mucho tiempo y tenía exactamente los mismos problemas. Terminamos creando nuestras propias CngKeys con ECDsa_P256 SHA256, pero creo que aprendí algo al profundizar en CryptoApi:

Cuando tienes un certificado marcado con "Autenticación del servidor (1.3.6.1.5.5.7.3.1) "(utilizar como certificado SSL), su certificado contendrá el algoritmo de intercambio de claves ECDH. Y de alguna manera esto "tiene prioridad" sobre el grupo de algoritmo ECDsa. Así obtienes el temido "El algoritmo de clave de certificado no es compatible".

Pasé más de una hora con Symantec mirando por encima de mi hombro y no pudieron resolver el rompecabezas, por lo que se dieron por vencidos con un "Lo sentimos, no admitimos el uso de certificados SSL para nada excepto SSL".

Puede obtener su CngKey privada del certificado con CLRSecurity de Codeplex (http://clrsecurity.codeplex.com/). Esto da a su X509Certificate2 una extensión que permite este código:

X509Certificate cer = <getyourcertcode>; 
CngKey k = cer.GetCngPrivateKey(); 

Inspeccionar "k" y ver que su grupo algoritmo es probablemente algo más de lo esperado. El mío fue ECDH ...

La solución que estoy intentando ahora es configurar un nuevo servidor de CA obligándolo a hacer exactamente lo que quiero. Básicamente que habría un certificado X509 que se utiliza sólo para la firma de código ...

"Uso de la clave X509v3: Firma Digital crítico" podría tener que ser el uso sólo se permite ...

Esperanza esto ayuda a otra persona por ahí :-)

+0

¿Cómo se puede crear una clave Cng desde solo una clave pública? Esa biblioteca CLRSecurity no parece proporcionar una extensión 'GetCngPublicKey()'. ¿Cómo puedo verificar una firma de ECDsa solo con la clave pública del firmante en un Certificado X509 en la tienda de certificados? –

+0

Eche un vistazo a mi respuesta aquí: http://stackoverflow.com/questions/10264770/creating-an-ecc-private-public-key-with-native-c-sharp/22637599#22637599. Verifique de esta manera: using (ECDsaCng ecsdKey = new ECDsaCng (CngKey.Import (clave, CngKeyBlobFormat.EccPublicBlob))) { if (ecsdKey.VerifyData (data, signature)) Console.WriteLine ("Data is good"); else Console.WriteLine ("Los datos son malos"); } –

+0

¿Parece que su respuesta no tiene nada que ver con los certificados X509 en la tienda de certificados? –

2

.NET 4.6.1 resolvió las necesidades principales de este problema.El nuevo código sería

... 
byte[] sig; 
using (ECDsa ecdsa = cert.GetECDsaPrivateKey()) 
{ 
    if (ecdsa == null) throw new Exception("Not an ECDSA cert, or has no private key"); 

    sig = ecdsa.SignData(data, HashAlgorithmName.SHA384); 
} 

.NET 4.6.1 también corrigió el problema por el cual algunas claves de cert vuelven como ECDH y fallan. (Bueno, no resolvió el problema de que algunas claves privadas se consideraran ECDH, lo cual no tenía nada que ver con Server Auth EKU, pero era una buena suposición), pero considera que esas claves son válidas ahora).

Cuestiones relacionadas