Is it possible within the limits of the X.509 specification to mark an intermediate CA as trusted for a specific purpose, e.g. to verify a VPN, HTTPS etc. server key, just like it would work with a root CA?

My VPN client(s) all have a way to explicitly provide a trusted CA certificate, which is used to verify the VPN server's authenticity. As long as I provide the root CA certificate, this works as expected - the certificate is trusted. (The intermediate certs are provided as part of the TLS handshake.)

However, I'm using an intermediate CA, and would very much like to provide that certificate, instead of the root CA. In my understanding of X.509, that should work:

The VPN server's key is signed by the intermediate CA, and as far as I understand X.509, that's all that is required to establish a trusted chain.

But in practice, it doesn't work: My VPN client doesn't connect.

In addition to VPN, I've tried this with 802.1X/EAPOL authentification, and multiple clients - with the same results: providing the root CA cert to the client works; providing my intermediate CA cert doesn't.

Is that by design, or is it just how most implementations work?

(I use a TLS based VPN, but as I've also tried it with 802.1X and TTLS, it seems to be related to TLS or X.509, and not to my specific VPN client/server architecture.)

Update:
I've fond an OpenSSL commit that implements adding non-self-signed CA certificates as trust anchors. Unfortunately, this is not yet included in any release version, so all the proposed workarounds in the comments still apply.

The trust chain is anchored by the root CA even for an intermediate CA. Do the clients have the root CA in their trust store?
–
zedman9991Jul 19 '12 at 12:37

Yes, they do. So it really is by design that the clients refuse to use the intermediate certs as roots of the validation process? Is that a consequence of the chain always being anchored by the root CA?
–
lxgrJul 19 '12 at 12:44

Not sure what is going on in your system but consider that root and intermediate CA certs are designed to issue certs which in turn do the lifting in the trust process.
–
zedman9991Jul 19 '12 at 13:02

4 Answers
4

A root CA is actually an illusion. In X.509, there are trust anchors. A trust anchor is, mostly, a name and a public key, which you know a priori and that you trust. Representation of that name and that public key as a "certificate file" (traditionally self-signed) is just a convenient way to keep the trust anchor as a bunch of bytes.

As per X.509, a CA is "intermediate" only if you do not trust it a priori; it is not an intrinsic property of the CA. What you need to do is convince your software to consider the CA as a trust anchor. One possible trick is to reencode the relevant data (the CA name and public key) as a (purportedly) self-signed certificate. Note that the self-signature is just a Tradition; it is there mostly because the file format for a certificate has a mandatory field for a signature. For a "root" CA, this signature has no significance (it makes little sense to verify it, since it would buy you nothing security-wise). Therefore, applications which use root CA certificates rarely verify that the signature is "self".

Therefore, you could build a custom "self-signed" certificate with the name of your "intermediate CA" as both SubjectDN and IssuerDN. For the signature, just put random junk bytes of approximately the right size (256 bytes for a 2048-bit signature). Then, try to set this pseudo-self-signed certificate as a root: chances are that it will work with your VPN. Alternatively, create your own root CA, and emit an extra certificate for the intermediate CA (you do not need the cooperation of the intermediate CA for that, you just need its name and public key, and you have these, in the intermediate CA certificate).

According to the RFC on Certificate Validation - RFC 3280 - Section 6.2:

The selection of one or more trusted CAs is a local decision. A
system may provide any one of its trusted CAs as the trust anchor for
a particular path. The inputs to the path validation algorithm may
be different for each path. The inputs used to process a path may
reflect application-specific requirements or limitations in the trust
accorded a particular trust anchor. For example, a trusted CA may
only be trusted for a particular certificate policy. This
restriction can be expressed through the inputs to the path
validation procedure.

It may be that you end up with some severe pain however - for example, if the policy extensions in the CA certificate indicate that it must be verified by CRL or OSCP - then you may have a legitimate hang in your application when it can't find the root CA to verify parts of this process -- for example CRLs may be signed by the root CA, so if the Root CA isn't available in the trust store, the application may not be able to deal with the situation.

It looks like, according to the RFC, you should be able to setup an Intermediate CA cert that can act as a trust anchor and you should be able to create a set of policy settings that work. I can say from experience, however, that you have entered the dubious realm of "maybe". You're proposing a non-standard configuration here that isn't the typical. Most times, the root CA is used here because it's the highest level thing out there, and in the long run, provisioning the trust anchor is usually hairy enough that folks are happy to go with the highest trusted power and avoid any need to add new CAs to the app over time. The realm of correctly setting policy extensions and getting the app to play along is Advanced PKI Vodoo - the error messages are often absurd, there is minimal tech support and it can take quite a bit of time to get it working correctly.

Sounds likely to be an implementation shortcoming, rather than a deliberate design decision.

Conceptually, if you add the intermediate CA cert to your set of trust anchors (CAs who you trust and thus will accept stuff signed by them), then a client should be willing to accept other certs signed by that CA, even if that CA is not the root in the chain. That would be an eminently reasonable way for a client ot behave. However, this may be a use case that isn't very common and that the application developers didn't consider, so their code might happen to not support it. C'est la vie.

The system is working as it was intended. By definition, an intermediate certificate is issued by, and relies on the trust relationship given to it by the trust between the client and the Root CA's certificate. The Root CA is self-signed and trusted by the client, the Intermediate CA is signed by the Root CA.

In simple terms, the Intermediate CA says "hey, I'm a CA, you can trust me because I'm signed by the Root CA that you already trust". The client then looks to see if indeed they trust the Root CA and if that trust relationship has been established, the certificate hierarchy (certificate chain) is validated and the certificate can be used.

By using certain fields and methods (certificate templates, OID's, Enhance Key Usage field, etc) you can specify what a given certificate is good for, but the whole scheme relies on the client trusting the root of the certificate chain.