EldoS | Feel safer!

Software components for data protection, secure storage and transfer

Certificate pinning and validating an incomplete chain

Also by EldoS: BizCrypto
Components for BizTalk® and SQL Server® Integration Services that let you securely store and transfer information in your business automation solutions.
#33608
Posted: 06/09/2015 09:36:18
by OGAlex (Standard support level)
Joined: 06/08/2015
Posts: 13

I'm using the TElX509CertificateValidator to pin a certificate on a Windows Phone 8.1 project. The server in question does not provide the root certificate.

I'm currently using the following event handler:

Code
private void OnCertificateValidate(object sender, TElX509Certificate certificate, ref bool validate)
        {
            if ((certificate.Chain == null || certificate.Chain.get_Certificates(0) == certificate))
            {
                TSBCertificateValidity validity = TSBCertificateValidity.cvInvalid;
                int reason = 0;
                certificateValidator.ValidateForSSL(certificate, "", "", TSBHostRole.hrServer, null, true, false, DateTime.Now, ref validity, ref reason);

                if (validity == TSBCertificateValidity.cvOk)
                {
                    validate = true;
                }
                else
                {
                    validate = false;
                }
            }
            else
            {
                validate = true;
            }
        }


I have provided the server certificate to the validator using the AddTrustedCertificates method, and get a response of cvChainUnvalidated, with reason vrUnknownCA.

How do I fix this? UseSystemStorages is not available in the WinStore assemblies. I basically want to do two things here: 1) verify that a certificate I provide is in the chain somewhere. 2) ensure that the entire chain is validated against the CAs stored on the windows phone device. Does Windows do the latter underneath the HttpBlackbox library? If no, Is this possible?
#33609
Posted: 06/09/2015 09:49:51
by Eugene Mayevski (EldoS Corp.)

Thank you for contacting us.

Quote
Alex wrote:
1) verify that a certificate I provide is in the chain somewhere.


The easiest way to do this is to capture all certificates passed to OnCertificateValidate by putting them to the instance of TElMemoryCertStorage, then to analyze what you have received and whether it constitutes a complete chain. It's possible that you have a trusted root (added off-line) and the end-entity certificate (received from the server) but don't have an intermediate CA certificate.

Quote
Alex wrote:
2) ensure that the entire chain is validated against the CAs stored on the windows phone device. Does Windows do the latter underneath the HttpBlackbox library? If no, Is this possible?


No and no. On Windows Phone there's no access to the system storage, so SecureBlackbox does everything on its own. The best option is to capture some CA and ROOT certificates (just take them from Windows) and include with your application. All in all Firefox browser has its own collection of certificates and you can do the same. Also the set of known certificates on the phone is smaller than on "large" Windows, and we saw problems when the site can be connected on desktop but not on Windows Phone due to reduced set of known roots.


Sincerely yours
Eugene Mayevski
#33639
Posted: 06/11/2015 07:14:04
by OGAlex (Standard support level)
Joined: 06/08/2015
Posts: 13

Quote
Eugene Mayevski wrote:
Quote
Alex wrote:
1) verify that a certificate I provide is in the chain somewhere.


The easiest way to do this is to capture all certificates passed to OnCertificateValidate by putting them to the instance of TElMemoryCertStorage, then to analyze what you have received and whether it constitutes a complete chain. It's possible that you have a trusted root (added off-line) and the end-entity certificate (received from the server) but don't have an intermediate CA certificate.



Thank you for your help, your answers were very helpful.

I don't think I explained myself clearly on the first question. This is the situation I have:

root CA (not sent by the server) -> intermediate CA (sent by the server) -> server cert (sent by the server)

I have verified this is the case, the certificate chain passed to the OnCertificateValidate event includes 2 certificates, the intermediate and the server certs.

If I provide only the server cert to the validator using AddTrustedCertificate, ValidateForSsl returns a cvChainUnvalidated with reason 32 vrUnknownCA. However, this is strange to me. If I explicitly trust the server cert, why would the validator complain that a CA is unknown?

If I provide only the intermediate cert OR if I provide the intermediate cert and the root cert, ValidateForSsl returns a cvInvalid with reason 512 vrIdentityMismatch. I'm not sure what the cause of this could be.

If I provide all 3, I finally get a cvOk.

However, I want to allow the user of my library to pin an intermediate CA. I also don't want them to have to provide the root CA, because there will inevitably be mixups where they add a root CA as trusted instead of known.

What are my options? I was thinking I could allow a cvChainUnvalidated as valid, but that still leaves the issue of when an intermediate CA is provided and the identity mismatch.
#33645
Posted: 06/11/2015 09:45:44
by Eugene Mayevski (EldoS Corp.)

Please check if you have ForceCompleteChainValidationForTrusted set to false (if it's true, then the certificate is still validated).

Also it would be nice if you could post your certificates to the HelpDesk where we could check them and see why the situation you describe happens. I don't think this is an issue of the validator but maybe some additional tuneup is needed in your case, and without having the certificates it's not possible to guess, what it is.


Sincerely yours
Eugene Mayevski
#33646
Posted: 06/11/2015 09:48:03
by OGAlex (Standard support level)
Joined: 06/08/2015
Posts: 13

I've additionally tested it by adding the root CA and the intermediate CA to AddKnownCertificates. Then the server certs to AddTrustedCertificates.

That still gives me a cvChainUnvalidated, but with reason 0? Very strange.

Edit: my apologies, hadn't seen the response yet. will check that out first

Edit 2:


Code
certificateValidator = new TElX509CertificateValidator();
certificateValidator.CheckCRL = false;
certificateValidator.CheckOCSP = false;
certificateValidator.ClearTrustedCertificates();
certificateValidator.ClearKnownCertificates();
//certificateValidator.AddTrustedCertificates(trustedCerts);
certificateValidator.ForceCompleteChainValidationForTrusted = false;


This setup, without any trusted certificates in the validator, is returning cvOk when I call:

Code
certificateValidator.ValidateForSSL(certificate, "https://mytestserver.com", "", TSBHostRole.hrServer, null, true, false, DateTime.Now, ref validity, ref reason);


I thought this method would check for a trusted certificate but I assume it isn't because of the false ForceCompleteChainValidationForTrusted. But if I set that to true, I get a cvchaininvalid by providing only the server cert or intermediate cert as trusted.

I want to have the ability to provide:
- the intermediate cert, WITHOUT trusting or even knowing the root CA and return valid
- the server cert, WITHOUT trusting or even knowing the root CA AND intermediate CA and return valid
- root cert, return valid
- another cert or no cert, return invalid

Is there another way to manually check that the server certificate, OR the intermediate certificate that I receive from the server are identical to a cert that I load from the file system?
#33854
Posted: 07/02/2015 05:19:38
by Eugene Mayevski (EldoS Corp.)

Unfortunately your description causes more questions than answers. Let's try to re-phrase your descriptions, please.

Let's start from the end of your message.


Quote
Alex wrote:
Is there another way to manually check that the server certificate, OR the intermediate certificate that I receive from the server are identical to a cert that I load from the file system?


I am afraid the Certificate Validator class doesn't work this way. It does not "check if certificates are identical" . It checks *validity* as defined and according to the rules set by the RFCs (standards). The certificates are not compared (neither binary nor property-by-property).

If you want to just compare the certificates, maybe binary comparison of their BLOBs is what you actually need. In this case the rest of your questions is just not applicable and you should not use TElCertificateValidator at all.


Quote
Alex wrote:
I thought this method would check for a trusted certificate but I assume it isn't because of the false ForceCompleteChainValidationForTrusted. But if I set that to true, I get a cvchaininvalid by providing only the server cert or intermediate cert as trusted.


On Windows the code you posted will validate the server certificate against the OS-provided trusted and known certificates. You can turn off the use of system-provided certificates, if needed.

Could you please elaborate what you meant by "would check for a trusted certificate" - did you think it would require a trusted certificate or how else should it "check for" it?

Quote
Alex wrote:
- the intermediate cert, WITHOUT trusting or even knowing the root CA and return valid


What do you mean by "and return valid"? Did you want to write "I would like to check validity of the provided intermediate certificate"?

The same question applies to the rest of statements.


Sincerely yours
Eugene Mayevski
#33855
Posted: 07/02/2015 05:46:38
by OGAlex (Standard support level)
Joined: 06/08/2015
Posts: 13

Hi Eugene, thanks for your response. My apologies for not being very clear, and perhaps I've misunderstood how PKI works.

I am simply trying to pin a certificate as per this article (https://www.eldos.com/security/articles/8103.php), specifically, the "Solution" section. My app holds a copy of the server certificate (or intermediate cert, I don't know which certificate will be present in the app assets), and I want to perform the additional check that the presented cert is likely to be real.

Quote
I am afraid the Certificate Validator class doesn't work this way. It does not "check if certificates are identical" . It checks *validity* as defined and according to the rules set by the RFCs (standards). The certificates are not compared (neither binary nor property-by-property).


But at some point there needs to be trust, correct? Usually the trust comes from a root cert on the device that is trusted. But the whole point of certificate pinning is that perhaps you don't trust the root CA. Instead, you trust an intermediate CA, or even only the server certificate. Is my understanding of certificate pinning incorrect?

Quote
On Windows the code you posted will validate the server certificate against the OS-provided trusted and known certificates. You can turn off the use of system-provided certificates, if needed.


Previously in this thread you mentioned that this does not occur on Windows Phone. The option to turn this off is not available in WinStore assemblies.
#33857
Posted: 07/02/2015 06:34:01
by Eugene Mayevski (EldoS Corp.)

Quote
Alex wrote:
I am simply trying to pin a certificate as per this article (https://www.eldos.com/security/articles/8103.php), specifically, the "Solution" section. My app holds a copy of the server certificate (or intermediate cert, I don't know which certificate will be present in the app assets), and I want to perform the additional check that the presented cert is likely to be real.


That can be done by simply comparing the binaries as I described (use SaveToBuffer method to save two certificates, then compare the buffers).

Quote
Alex wrote:
But at some point there needs to be trust, correct? Usually the trust comes from a root cert on the device that is trusted. But the whole point of certificate pinning is that perhaps you don't trust the root CA. Instead, you trust an intermediate CA, or even only the server certificate. Is my understanding of certificate pinning incorrect?


When you add an intermediate (or a root) CA as trusted to the certificate validator using AddTrustedCertificates() method, you say "I want to accept only certificates signed by this trusted CA". You would also need to turn off the use of system certificates, to make your trusted one exclusive.
Such claim says that you trust the certificate you provide to be a CA.

Quote
Alex wrote:
Instead, you trust an intermediate CA, or even only the server certificate. Is my understanding of certificate pinning incorrect?


That's correct. The question is that CheckIfTrusted internal method of
the certificate validator works by simply searching for the certificate with the same ID in the list of trusted certificates. It doesn't compare certificate binaries. You can do such comparison in OnAfterCertificateValidation event handler, which lets you perform post-checks and possibly alter the default behavior / results of the certificate validator.

Quote
Alex wrote:
Previously in this thread you mentioned that this does not occur on Windows Phone. The option to turn this off is not available in WinStore assemblies.


In SecureBlackbox 13 there exists a way to use system storages in some assemblies (for WP 8.1, if memory serves). Also I am describing all possibilities, as other users will also read this thread, and they need to be aware that system certificates can be implicitly used in some cases.


Sincerely yours
Eugene Mayevski
#33861
Posted: 07/02/2015 07:52:46
by OGAlex (Standard support level)
Joined: 06/08/2015
Posts: 13

Quote
When you add an intermediate (or a root) CA as trusted to the certificate validator using AddTrustedCertificates() method, you say "I want to accept only certificates signed by this trusted CA". You would also need to turn off the use of system certificates, to make your trusted one exclusive.


Yes, this is exactly what I want! And exactly what the article I linked describes. It states: Add your pinned certificate to AddTrustedCertificates(), and turn off system certificates.

I did exactly that (since system certificates are automatically off in Windows Phone). But like I said:

1) If ForceCompleteChainValidationForTrust is true, I get a cvChainUnvalidated. Even if I add the root cert to known certificates (this changes the reason from 32 to 0??)! I cannot get a cvOk.
2) If ForceCompleteChainValidationForTrust is false, I get cvOk, even if I don't add any trusted certificates!

The first is unacceptable because I need to get a cvOk if the intermediate certificate is trusted, and the second is unacceptable because I should get a cvInvalid (or something else) if I don't trust any certificates.

I'm simply confused because the article implies the certificate validator can do certificate pinning, however it appears it can't. If this is indeed the case, I will resort to comparing the binaries you suggest. But perhaps the article should be amended.

I uploaded the relevant certificates last time, if you need to take a look.
#33870
Posted: 07/02/2015 12:45:15
by Eugene Mayevski (EldoS Corp.)

Quote
Alex wrote:
1) If ForceCompleteChainValidationForTrust is true, I get a cvChainUnvalidated. Even if I add the root cert to known certificates (this changes the reason from 32 to 0??)! I cannot get a cvOk.


This behavior is correct - known is not trusted. If you add the root to Trusted, you'll get Validation result as cvOk. If you add the root to known, you get ChainInvalid as the reason.

The idea of the certificate path validation is that your certificate chain must end with a trusted certificate.

Quote
Alex wrote:
2) If ForceCompleteChainValidationForTrust is false, I get cvOk, even if I don't add any trusted certificates!


Emm, you get ok because you've set the certificate itself as trusted, no?
If you add nothing, the certificate being validated can not become valid unless there's a system certificate storage used implicitly. I see no way for the certificate to be treated as trusted.

BTW you are passing not a correct parameter as a server name. "https://mytestserver.com" is an URI, not a server name. The server name is "mytestserver.com".

ValidateForSSL would not return cvOk on the certificate in your call as it matches the passed name and the name in the certificate. Something must be wrong with your code (i.e. you've written not the code you tested).


Sincerely yours
Eugene Mayevski
Also by EldoS: CallbackFilter
A component to monitor and control disk activity, track file and directory operations (create, read, write, rename etc.), alter file data, encrypt files, create virtual files.

Reply

Statistics

Topic viewed 3429 times

Number of guests: 1, registered members: 0, in total hidden: 0




|

Back to top

As of July 15, 2016 EldoS Corporation will operate as a division of /n software inc. For more information, please read the announcement.

Got it!