Archivo de firma ECDSA con clave de la tienda C#.Net CNG
cryptography elliptic-curve (3)
.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 solucionó el problema donde algunas claves de certificado vuelven a ser ECDH y, por lo tanto, fallan. (Bueno, no resolvió el problema de algunas claves privadas que se consideraban ECDH, que no tenían nada que ver con el Server Auth EKU, pero era una buena suposición, pero considera que esas claves son válidas ahora).
Estoy intentando firmar un archivo con ECDSA utilizando la API de CNG y un certificado del Almacén de certificados de Microsoft. He leído un montón de documentación y casi he terminado, pero me he quedado colgado al importar 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:
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: el algoritmo de clave de certificado no es compatible.
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)
Parece como si el certificado fuera 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
He estado luchando ECDsa y CngKey con certificados X509 durante un tiempo prolongado y tuve exactamente los mismos problemas. Terminamos creando nuestros propios CngKeys con ECDsa_P256 SHA256, pero creo que aprendí algo al analizar CryptoApi:
Cuando tenga un certificado que esté marcado con "Autenticación del servidor (1.3.6.1.5.5.7.7.1) (uso 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. De este modo se obtiene el temido "No se admite el algoritmo de clave de certificado".
Pasé más de una hora con Symantec mirando por encima del hombro y no pudieron resolver el rompecabezas, así que se dieron por vencidos con un "Lo sentimos, no admitimos el uso de certificados SSL para nada más que SSL".
Puede obtener su CngKey privado del certificado con CLRSecurity de Codeplex ( http://clrsecurity.codeplex.com/ ). Esto le da a su x509Certificate2 una extensión que permite este código:
X509Certificate cer = <getyourcertcode>;
CngKey k = cer.GetCngPrivateKey();
Inspeccione "k" y vea que su grupo de algoritmos es probablemente algo más de lo esperado. El mío era 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, ese sería un certificado X509 que SOLO se usa para la firma de código ...
"Uso de la clave X509v3: Firma digital crítica" debe ser el ÚNICO uso permitido ...
Espero que esto ayude a alguien más por ahí :-)
Si está ejecutando Windows Vista o Windows 2008, no se admite CngKeyBlobFormat.EccPrivateBlob. ¿Qué sistema operativo estás usando? CngKey.Import lanza la excepción CryptographicException solo en algunas máquinas