Following the guides here and here I am setting up a multi-level PKI. I have increased the pathlen config to 3, such that I can generate one root certificate that I can use to sign the first intermediate and store securely. The first intermediate will be stored on the configuration workstation and be used to generate second intermediates, which will be used to generate the final certificates actually used for communication within a remote cluster.
In experimenting around with this I found that if I reduce the pathlen value used to generate the CA, even to 0, then in a command such as this:
openssl verify -CAfile <root ca> -untrusted <chain of intermediates> \ <cert to verify>
the certificate is still validated as OK.
Since asking a question on this here I also set up a similar trust chain using openssl (1 CA, 2 intermediate CAs, 1 server certificate) and assigned the pathlen "1" to the CA, and pathlen "0" to both intermediates (one intermediate was signed by the other).
openssl verify still said this was OK.
I would have expected the Max Path Length of the CA to make the leaf certificates in both cases invalid, is this wrong?
Update: Outcome (hopefully to illustrate the understanding I've gained)
It turns out that when I was verifying the chain I set up via openssl, I was verifying the second subordinate trust certificate, rather than the server (leaf) certificate. When I set up a chain of the two subordinates to pass to the
-untrusted flag, and verified the server certificate, openssl (correctly) rejects this as invalid.
This means that the minimum number of trusts for a valid certificate where a pathlen constraint is enforced is 2 - the root (self-signed) CA, where any pathlen value is ignored, and an intermediate certificate (which can have a pathlen value of 0 at minimum). Note that even though the pathlen is 0, a valid certificate can still be signed by this intermediate, as the pathlen constraint only applies to the number of nodes in the certificate's trust chain, not the certificate itself.
The author of the articles I was using as source information on this gets this wrong. Additionally the way cfssl at time of writing is set up to accept a pathlen value for a self-signed CA value only (not for any subordinate CA) makes this even more opaque, and probably caused the confusion on the part of the author.
In retrospect, it makes sense that a pathlen value would not need to be applied to a root CA, as the CA is ultimately trusted (or should be for any signed certificates to be valid). It is on the authority maintaining the root CA key to sign any CSRs requesting CA status or not (including checking the pathlen value), depending on their policy.