views:

190

answers:

1

I am trying to validate an X.509 certificate using C# and .NetCF. I have the CA certificate, and if I understand correctly, I need to use the public key from this CA certificate to decrypt the signature of the untrusted certificate. This should give me the computed hash value of the untrusted certificate. I should then compute the hash of the certificate myself and make sure the two values match.

I've been playing with this for a few days and I'm not getting very far. I've been using the X509Certificate and RSACryptoServiceProvider classes. First, I tried to get the public key and signature out of the X509Certificate class. I was able to get the public key but not the signature. Next, I tried parsing the binary data that made up the certificate, which allowed me to get the signature (and any other data I wanted), but I was unable to decrypt the signature using the RSACryptoServiceProvider. I tried things like this but kept getting exceptions saying "Bad Key" when I tried to decrypt:

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

Any advice would be greatly appreciated.

Edit: I tried something that seems to be better but is returning a strange result. I'm working with the X509Certificate2 class here because it's a little easier for testing, but I will need to switch to X509Certificate for .NetCF later. I think that RSACryptoServiceProvider.VerifyData might be what I need. I tried the following code.

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);

As I said, I am able to manually decode and interpret the binary data of the certificate, so I'm pretty sure the cert.RawData is the certificate's signed data and the last 256 bytes are the encrypted signature. The string is the OID of the hash algorithm, which I got from certificate, but I'm not 100% sure that it's correct. VerifyData returns false, but I'm not sure why yet.

Thoughts?

+1  A: 

Does WinCE support something compatible with the Win32 MSCrypto.dll? If yes, take a look at the .NET X509Certificate2 class and also the CLR Security library on Codeplex. It contains a lot of helpful routines for .NET that sit on top of the core OS crypto library. You can download the source and see how it compiles for .NetCF

To load and validate an X509 certificate, do something like this (untested):

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

There are nearly a dozen constructors for X509Certificate2 to construct from a wide variety of sources - file on disk, byte array in memory, load from local cert store, etc.

The root CA used to sign the certificate will need to be installed in the local cert store. If the certificate does not include the intermediate CAs in the trust chain, those intermediates will need to be on the local machine too, all the way up to a root CA that is in the trusted cert store in the local machine.

Unfortunately, I can't tell from the MSDN docs whether X509Certificate2 is available on .NetCF.

dthorpe
WinCE's limitations can be rough and I'm completely new to X.509, so I've actually been trying to get this working in a normal Win32 environment first and I'm even unable to do that. I took a look at the CLR Security library that you pointed to, but I didn't see anything there to validate the X509 certificate. Can you give me a little more to go on?
Ben
I updated the answer with sample code.
dthorpe
X509Certificate2 is not available on .NetCF, but this is helpful. Thanks.
Ben