Can an intermediate CA be trusted like a self-signed root CA?
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.