2010-09-02 53 views
7

Estoy intentando validar un certificado X.509 usando C# y .NetCF. Tengo el certificado de CA, y si lo entiendo correctamente, necesito usar la clave pública de este certificado de CA para descifrar la firma del certificado que no es de confianza. Esto debería darme el valor hash calculado del certificado que no es de confianza. Entonces debería calcular el hash del certificado yo mismo y asegurarme de que los dos valores coinciden.Cómo validar el Certificado X.509 en C# usando Compact Framework

He estado jugando con esto por unos días y no estoy llegando muy lejos. He estado usando las clases X509Certificate y RSACryptoServiceProvider. Primero, traté de obtener la clave pública y la firma de la clase X509Certificate. Pude obtener la clave pública pero no la firma. A continuación, traté de analizar los datos binarios que formaban el certificado, lo que me permitió obtener la firma (y cualquier otro dato que quisiera), pero no pude descifrar la firma con el RSACryptoServiceProvider. He intentado cosas como esta, pero cuidado para conseguir excepciones diciendo "Bad clave" cuando trataba de descifrar:

RSAParameters rsaParams = new RSAParameters(); 
rsaParams.Exponent = exp; 
rsaParams.Modulus = mod; 
RSACryptoServiceProvider rsaServ = new RSACryptoServiceProvider(); 
rsaServ.ImportParameters(rsaParams); 
byte[] decryptedSig = rsaServ.Decrypt(encryptedSig, false); 

Cualquier consejo sería muy apreciada.

Edit: Probé algo que parece ser mejor pero está dando un resultado extraño. Estoy trabajando con la clase X509Certificate2 aquí porque es un poco más fácil de probar, pero tendré que cambiar a X509Certificate para .NetCF más adelante. Creo que RSACryptoServiceProvider.VerifyData podría ser lo que necesito. Probé el siguiente código.

X509Certificate2 cert = new X509Certificate2(certBytes); 
X509Certificate2 certCA1 = new X509Certificate2(@"C:\certs\certCA1.cer"); 

byte[] encryptedSig = new byte[256]; 
Array.Copy(certBytes, certBytes.Length - 256, encryptedSig, 0, 256); 

RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)certA1.PublicKey.Key; 
bool good = rsa.VerifyData(cert.RawData, "1.3.14.3.2.26", encryptedSig); 

Como ya he dicho, soy capaz de decodificar e interpretar los datos binarios del certificado manualmente, así que estoy bastante seguro de que el cert.RawData es datos firmados del certificado y los últimos 256 bytes son la firma cifrada . La cadena es el OID del algoritmo hash, que obtuve del certificado, pero no estoy 100% seguro de que sea correcto. VerifyData devuelve falso, pero todavía no estoy seguro de por qué.

¿Pensamientos?

Respuesta

3

Aquí es mi código.

RSACryptoServiceProvider rsa = signingCertificate_GetPublicKey(); 
return rsa.VerifyData(SignedValue(), CryptoConfig.MapNameToOID("SHA1"), Signature()); 

RSACryptoServiceProvider signingCertificate_GetPublicKey() 
{ 
    RSACryptoServiceProvider publicKey = new RSACryptoServiceProvider(); 

    RSAParameters publicKeyParams = new RSAParameters(); 
    publicKeyParams.Modulus = GetPublicKeyModulus(); 
    publicKeyParams.Exponent = GetPublicKeyExponent(); 

    publicKey.ImportParameters(publicKeyParams); 

    return publicKey; 
} 

byte[] GetPublicKeyExponent() 
{ 
    // The value of the second TLV in your Public Key 
} 

byte[] GetPublicKeyModulus() 
{ 
    // The value of the first TLV in your Public Key 
} 

byte[] SignedValue() 
{ 
    // The first TLV in your Ceritificate 
} 

byte[] Signature() 
{ 
    // The value of the third TLV in your Certificate 
} 

Espero que ayude a cualquiera que esté trabajando en este problema.

1

¿WinCE admite algo compatible con Win32 MSCrypto.dll? En caso afirmativo, eche un vistazo a la clase .NET X509Certificate2 y también al CLR Security library on Codeplex.. Contiene muchas rutinas útiles para .NET que se encuentran en la parte superior de la biblioteca de cifrado del sistema operativo principal. Puede descargar el código fuente y ver cómo se compila para .NetCF

Para cargar y validar un certificado X509, hacer algo como esto (no probado):

var cert = new X509Certificate2("mycert.cer"); 
if (!cert.Verify()) 
{ 
    <fail> 
} 

hay cerca de una docena de constructores para construir X509Certificate2 desde una amplia variedad de orígenes: archivo en disco, matriz de bytes en la memoria, carga desde el almacén de certificados local, etc.

La CA raíz utilizada para firmar el certificado deberá instalarse en el almacén local de certificados. Si el certificado no incluye las CA intermedias en la cadena de confianza, los intermediarios también deberán estar en la máquina local, hasta llegar a una CA raíz que se encuentre en la tienda de certificaciones de confianza en la máquina local.

Desafortunadamente, no puedo decir desde los documentos de MSDN si X509Certificate2 está disponible en .NetCF.

+0

Las limitaciones de WinCE pueden ser difíciles y soy completamente nuevo en X.509, así que he estado tratando de hacer que esto funcione en un entorno Win32 normal primero y ni siquiera puedo hacerlo. Eché un vistazo a la biblioteca CLR Security a la que me apuntó, pero no vi nada allí para validar el certificado X509. ¿Puedes darme un poco más para seguir? – Ben

+0

Actualicé la respuesta con código de muestra. – dthorpe

+0

X509Certificate2 no está disponible en .NetCF, pero esto es útil. Gracias. – Ben

0

Me funciona en Win32, pero en Compact Framework que se me presentan el mismo problema, no hay X509Certificate2 así que estoy realmente bloqueado, con win32 que podemos hacer:

X509Certificate2 l__PublicKeyCertificate = new X509Certificate2("cert.cer"); 

RSACryptoServiceProvider l__rsaCspPublic = (RSACryptoServiceProvider)l__PublicKeyCertificate .PublicKey.Key; 

//... 

l__isVerified = l__rsaCspPublic.VerifyData(l__fileData, CryptoConfig.MapNameToOID("SHA1"), l__fileSignature); 
+0

Me di cuenta de esto hace un tiempo y olvidé publicar la respuesta. Echaré un vistazo a mi código fuente y recibiré la respuesta el lunes. – Ben

Cuestiones relacionadas