Validate if certificate is revoked - c#

I have the following situation:
Java Applet for digital signature - on client side
Validation of digital signature and digital certificate - on server side
I'm using the following C# code to validate the signature and the certificate:
ContentInfo content = new ContentInfo(pdf);
SignedCms signedMessage = new SignedCms(content, true);
signedMessage.Decode(assinatura);
signedMessage.CheckSignature(false);
Where:
pdf - signed pdf file
assinatura - pdf's signature - in my case, the signature it's not with the pdf file
By the tests I made, the code validate the certificate chain, the expiration and others...
However, I would like to know a few things:
This code validates that the certificate used for signing is revoked? If it does not validate, how could I make such a validation system at this point?
Is there a way to create a certificate that is revoked for testing?

Revocation check is performed by
Obtaining CRL that can contain information about the status of the certificate
Sending OCSP request to the server authorized to respond to such requests
If OCSP server's URL is present, OCSP is the preferred (for security) method to check revocation, but in general both checks should be performed.
OCSP and CRL operations are supported by our SecureBlackbox, CryptLib, BouncyCastle. In SecureBlackbox you will find a high-level CertificateValidator class which does all checks for you (at the same time letting you interfere in all aspects of the procedure).
There's no way to create a revoked certificate unless you run your own private certificate authority (but if you did, probably there would be no question). The reason is that you can't put your certificate's ID to the CRL sent by CA (or make the third-party OCSP responder do this).
Oh, I can see one way - buy a certificate, then contact the CA and tell them that you've disclosed the private key. They will block the certificate. But this is quite costly method :).

Related

How to implement certificate pinning for a TcpClient

I'm trying to set up a TCP stream (non-HTTP) on a server that will be exposed to the public internet, but only "chosen" clients should be able to connect to. As I understand it, this is generally handled by certificate pinning, but I'm not familiar with all the details of how this is done.
Generate a SSL cert for the server. That's easy enough.
Set up the server. Have it call something like the following when a client connects:
private SslStream GetSslStream(TcpClient client, string certificateFile)
{
var c = X509Certificate.CreateFromCertFile(certificateFile);
var cert = new X509Certificate2(c);
if (!cert.Verify()) {
throw new Exception("Certificate failed verification");
}
var stream = new SslStream(client.GetStream(), false, VerifyClientCert);
stream.AuthenticateAsServer(cert, true, true);
return stream;
}
Where does the client certificate come from? Is it a copy of the server's SSL certificate? Is it a separate cert that has to be derived from the server's cert in some way? Is it a completely different cert?
What goes in the VerifyClientCert method to make sure it's the right certificate? Just Verify() and check the Thumbprint against an expected value, or is there more that needs to happen?
Should every client get a copy of the same client cert?
Certificate pinning is a different concept. When server uses SSL certificate, it's usually issued by some Certificate Authority. Certificate of that authority can in turn be issued by yet another Certificate Authority, forming a chain. When client validates server certificate, it checks if that Certificate Authority is "trusted" by this particular client. "Trusted" in turn means that some certificate in the chain described above is trusted by this client. For example, Windows and Linux OS both come with certain set of Certificate Auhorities trusted by default. If server certificate has some of those authorities in their chain - then it's also trusted.
Certificate pinning means you, as a client, impose more restrictions on server certificate than what is described above. For example, you might say that for this domain \ endpoint, I only trust this specific certificate (with this specific digest), and I do not care about trust chain at all. Or that for this endpoint I only trust this specific Certificate Authority. This is certificate pinning. You can use it for your server, but it has its drawbacks which I won't describe here.
Now back to your problem. What you describe is called Client Certificate Authentication. In SSL handshake, not only server can present certificate for client to verify. Server might also request client to send his own certificate, to authenticate that client. This certificate is of course completely different from server's certificate.
Every client must have different certificate. Usually one of the two options are used:
You (server owner) create your own Certificate Authority (for example with couple of simple openssl commands), and then you issue separate certificate for each client from this authority. Then you send those certificates (one for each client), including private keys, to their respective clients. After that you can throw away (delete) those certificates, because you will no longer need them. When validating client certificate - just check if it was issued by your Certificate Authority.
OR separate certificate is issued for each client and you store thumbprints (digests\hashes) of those certificates, one for each client. Then during validation you ensure that Thumbprint has the expected value for given client. The benefit is that you can ask client to generate such certificate and send you (the server owner) the thumbprint. Then you never had private key of that certificate in your possession (unlike method with your own Certificate Authority where you generated certificate yourself and at one point posessed its private key).

Use certificate when issuer is not is X509Store trusted roots for client authentication using Microsoft .NET framework

While working on this question, I identified that the problem is slightly different than initially stated, so I am changing title and description
I'm trying to authenticate myself against WebService using my client certificate. I am using WebRequest for that purpose. I need to use self-signed certificate, without registering it in Windows X509 trusted root store.
The way I know if client certificate is presented or not is by examining request object on the server
I tried to use code from this question as a guidance. It doesn't work on .NET. Here is my code:
var certificate = new X509Certificate2(Properties.Resources.MyCert);
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(host);
req.ClientCertificates.Add(certificate);
WebResponse resp = req.GetResponse();
var stream = resp.GetResponseStream();
What I observe is that even though req.ClientCertificates does contain certificate with a valid private key, that certificate is never presented to server. I get no indication from WebClient that certificate is not used during handshake.
If I put certificate into "trusted root", the code will work (even when certificate is not in "personal").
My questions are:
Since certificate is usable when it's placed in "trusted root", I assume it is likely due to policy or something of that kind. Is it possible to coerce .NET to ignore policy settings and use supplied client certificate during TLS negotiation?
If abovementioned coercion is not possible, is there a call which will tell me ahead of time, that certificate I am about to use is not usable, and will be ignored? Alternatively, if such call is not available, could I make WebClient fail indicating a certificate error, instead of silently skipping over?
NOTE: I am aware that configuring certificates as described by Microsoft will work. This is NOT what I am looking for. I don't want to register potentially insecure certificate in trusted root, because this is potentially security hazard. I want to use cert on client without registering in store, or at least to get an exception indicating that certificate cannot be used. I realize that there can be multiple reasons why certificate cannot be used for a session, but there must be an exception, or at least some sort of indication on the client side that it cannot use specified cert. Instead, client simply doesn't present one.
When you instantiate your X509Certificate2, is the PrivateKey property set? If it is null, you are missing the private key, meaning the SSL/TLS client will be unable to authenticate you.
Make sure you are loading the certificate from a PFX file (or similar) instead of a CER. These contain the private key, too. They are usually password protected for that purpose. See How to retrieve certificates from a pfx file with c#? for more info.

X509Certificate2.Verify behaviour

I have a digitally signed binary app.exe. Certificate is issued by commercial CA. In file properties (on Windows), Digital Signature information says that This digital signature is OK. If I somehow modify binary (e.g. by changing resources in Resource Hacker) Digital Signature information says that This digital signature is not valid.
I tried to verify certificate programmatically but X509Certificate2.Verify() returns true no matter which file I use - original (app.exe) or tampered one (app-modified.exe).
string filename = "app.exe"; // "app-modified.exe"
X509Certificate cert1 = X509Certificate.CreateFromSignedFile(filename);
X509Certificate2 cert2 = new X509Certificate2(cert1);
bool isValid = cert2.Verify();
Why does this function return true in both cases? Is this a proper way of validating digital signatures of files?
I think that you are misunderstanding the digital-signature verification process. Roughly verify digital-signature process consists in two steps, first step is validate the signature integrity (check that no one modify the document after signature is applied), and the second step is validate certificate status (check that certificate is valid, not expired or revoked).
So If you modify your signed app.exe you are broken your signature, but if the certificate was valid it remains valid which is the reason that in both cases your certificate validation is ok.
If instead of validate only the certificate you validate the signature the result will be false in the app-modified.exe because when you modify the app.exe you broke the signature.
Hope this helps,

SmartCard security, how do you authenticate the certificate as not fake?

I'm trying to develop an ASP.net site that reads the clientCertificate to ensure a smart card was used to access the website (trying to do away with username/password login).
The process I have in my mind is:
User registers an account and C# records user's clientCertificate (public).
The user can then log in the next time with that same clientCertificate, and they are now an authenticated user if hash valid.
I will use the code below to ensure authenticity of certificate. The browser should deal with private keys and ensure the certificate was NOT faked.
Based on Subject+certificate combination, C# assigns them their role-access.
The following code can be used for authenticity of certificate right?
X509Certificate x509Cert = new X509Certificate(Request.ClientCertificate.Certificate);
SHA1 sha = new SHA1CryptoServiceProvider();
byte[] hashvalue = sha.ComputeHash(Request.ClientCertificate.Certificate);
byte[] x509Hash = x509Cert.GetCertHash();
// compare x509Hash WITH hashvalue to ensure they are a match.
// If not, possibly faked certificate, not a real smartcard???
Is this how SmartCard authentication process should work???
If you just need to authenticate users with client certificates you should do this in IIS. You do not need to add any code at all to your application:
Specify Whether to Use Client Certificates (IIS 7)
Unless you need to link client certificates with database accounts or perform an additional validation step. But still for client certificate authentication I would stick with IIS settings.
Update:
In case you need to manipulate the client certificate you can do:
X509Certificate2 x509Cert2 = new X509Certificate2(Page.Request.ClientCertificate.Certificate);
And then access its properties such as:
x509Cert2.Subject
However, leave the validation piece up to IIS. If the client presents a bad certificate your asp.net code will not even execute since IIS will reject it
See this thread, sir. You do not need to verify authenticity explicitly in your code. IIS will do it for you.
Does IIS do the SSL certificate check or do I have to verify it?
IIS even tries to check revocation lists (however, this is often disabled if the CRL is large). An OCSP responder should be used to validate in cases where the CRL is very large or latency in checking it is high http://www.axway.com/products-solutions/email-identity-security/identity-security/va-suite.
Client-certificate authentication is done during the SSL/TLS handshake.
It is usually done using a Public Key Infrastructure, whereby the server has a (fixed) list of trusted CA certificates which it uses to verify the client certificate (in the same way as clients to it for the server). Once the certificate is presented to your application after this stage, you will know that:
the client has the private key for that certificate (guaranteed by the Certificate Verify message in the TLS handhsake (the SSL/TLS stack will verify this for you, no need to implement anything);
the client has the identity described in the certificate, because you will have verified it against your trusted CA.
The verification against a trusted CA requires the user to be registered with that CA in advance. You can't just authenticate any certificate if it hasn't been issued by a CA you trust. (Mapping the certificate's subject to a local user ID is another matter: you could do this upon first connection if needed: have your own database or directory service to map the Subject DN to another kind of user ID in your application, for example.)
User registers an account and C# records user's clientCertificate
(public). The user can then log in the next time with that same
clientCertificate, and they are now an authenticated user if hash
valid.
It sounds like you want to allow any certificate to be presented and use it for the initial registration, without necessarily resorting to a commonly trusted CA.
This is possible in principle, and I've done this to explore alternatives to PKI in Java.
To do this, you need to let any certificate through as far as the SSL/TLS handshake is concerned, and verify the certificate itself later. (You do need to use some form of verification.) You are still guaranteed with this that the client has the private key for the public key certificate it has presented.
Doing this requires two steps:
You need to be able to advertise the fact that you're going to accept any certificate, by sending an empty list of certification authorities in the Certificate Request TLS message (explicitly allowed by TLS 1.1).
Configure the SSL/TLS stack to trust any certificate (once again, when you do this, do not forget to implement your own verification system within your application, otherwise anything will really get through).
In .Net, while it should be possible to address the second point using a remote certificate validation callback, I have never found a way to alter the first point (this was also asked in this question).
In Java, the JSSE's X509TrustManager allows you to address both points.

Can I verify an XMLDSIG signature in .NET without requiring the root certificate be installed?

I'd like to use XMLDSIG for verifying that a .config file has not been tampered with. I also want to be able to verify the signature chain so that I can trust the signature.
I've got three certificates in the chain:
Root CA -> Intermediate Signing CA -> Signing Key
I check that the file is signed with a key that is issued by the intermediate CA.
I'd like to do this without installing any certificates in the user's Windows certificate store. These are self-signed certificates, so not every user is going to want me installing them in their Root store. I don't have a problem with installing them in my root store.
I have the original .CER files -- they're included in the Signature block, and I can include them with the verification code. I can build a certificate chain from this by using X509ChainPolicy.ExtraStore.
If the certificates are not installed in the root store, and I verify the chain, then X509Chain.Build returns false, and the chain has a X509ChainStatusFlags.UntrustedRoot in it.
Can I add trusted certificates just for the duration of this operation?
Assuming you have physical copies of the public keys of ALL signing certs in the trust chain, then this is possible by using the OpenSSL command line tool.
http://www.madboa.com/geek/openssl/#verify-standard
It's a bit of a steep learning curve at first, but a very powerful utility.
If you don't have the signing certs, then you cannot verify anything. That would be the same as trying to verify a human signature without having seen the original. You have nothing to compare to, so how could you verify the authenticity?
Update
There's something here perhaps that could help you:
http://social.msdn.microsoft.com/Forums/eu/clr/thread/1966a6e8-b6f4-44d1-9102-ec3a26426789

Categories

Resources