12

I'm trying to create an environment with cross-signed CAs, and verify a certificate issued against one of the CAs, all using openssl. The best I got so far is getting openssl into an endless loop while verifying (the loop is terminated at level 100).

I've published all of the certs I created. Now, there are a number of assumptions that I'm making, and largely based on this Oasis document to build the model. Here are my assumptions:

  1. There should be 4 certificates, self-signed from authorities #1 and #2, and cross-signed, where authority #1 is signed by authority #2 and vice versa.
  2. There are only 2 actual subjects (DNs) used (the same subject used by an authority for self-signed is what it has signed by the other authority, albeit in a different cert).
  3. All 4 certificates should be the part of the end-user trust.
  4. The keys used by the same authority, for both self- and cross- signed certificates should be the same
  5. AKI should not be used (May be "shouldn't" is too of a strong word, but not using it shouldn't hurt. Because of the same keys rule, it shouldn't matter though)
  6. I tried setting CA:TRUE for cross-signed certs, with the same result.

My understanding of cross-signing, is that it gives the verification process alternative paths. Considering that I see openssl loop, it seems to be picking cross-signed certificates every time. So the crux of the question is - what would make the verification process to favor the self-signed certificate over the cross-signed one, considering both have the same subject.

Here is a test leaf certificate, I can't make openssl verify to verify it successfully.

[vps@druid]~/ws/EF/pki3$  openssl verify -verbose -CAfile cas.pem cert.pem 
cert.pem: C = US, O = Excelfore, OU = PoC, CN = xl4 CA 2
error 2 at 100 depth lookup:unable to get issuer certificate
3

OK, this is the best that I came up with so far.

The problem with depth processing, I believe, is just OpenSSL's. It's not good that it can't build proper paths. RFC-5280, Sec 6.1 says:

A certificate MUST NOT appear more than once in a prospective certification path.

OpenSSL probably violates that. However, I have to say that I don't quite see an explanation in RFC-5280 on how to build paths, except for its Sec 3.2; there are suggestion that paths must end with a single self-signed CA at the end of each chain (that, however, contradicts with statements that verification chain should not have trust anchors, but trust anchors may contain intermediate certs, which makes the post-chain side contain multiple certificates, where OpenSSL ends up with infinite loop). Either way, I don't agree with what OpenSSL is doing.

I also should say that what I was talking about is not just cross signed certificates, but mutually cross signed certificates. The obvious difference is that normal cross-signed don't create such a circular dependency, and is achieved by having a trust anchor from one CA that is signed by another CA (from the perspective of verifier, it's the same case as a trusted intermediary, AFAIU).

The way to make it work with OpenSSL, is by not adding cross signed certs into the trust list, but provide them as part of the intermediate certificates produced by the key holder.

If I put all self-signed in trust.pem, all cross-certs in untrust.pem, then verifier works, albeit spews intermediate errors (which makes sense as not all trees build/verify successfully):

Here is with both roots present:

$  openssl verify -verbose -CAfile trust.pem -untrusted nontrust.pem host1/cert.pem 
host1/cert.pem: C = US, O = Excelfore, OU = PoC, CN = xl4 CA 1
error 24 at 1 depth lookup:invalid CA certificate
C = US, O = Excelfore, OU = PoC, CN = xl4 CA 2
error 24 at 2 depth lookup:invalid CA certificate
OK

Here is with only one or another root present:

$  openssl verify -verbose -CAfile ca1/ca1.pem -untrusted nontrust.pem host1/cert.pem 
host1/cert.pem: C = US, O = Excelfore, OU = PoC, CN = xl4 CA 1
error 24 at 1 depth lookup:invalid CA certificate
C = US, O = Excelfore, OU = PoC, CN = xl4 CA 2
error 24 at 2 depth lookup:invalid CA certificate
OK
$  openssl verify -verbose -CAfile ca2/ca2.pem -untrusted nontrust.pem host1/cert.pem 
host1/cert.pem: C = US, O = Excelfore, OU = PoC, CN = xl4 CA 1
error 24 at 1 depth lookup:invalid CA certificate
OK

Which shows the coolest part of the cross signing that we can nuke a CA, and still have original certs working.

HOWEVER

RFC-5246, Sec. 7.4.2 that documents TLS 1.2 says that the server has only one chain to present to the client (and vice versa). If the cross signed certs can not be part of the trust store, then then client has to provide multiple chains in order for the verifying side that there are options. So, yes, it works in theory, but not with SSL (it may work with other verification protocols, I didn't check), at least in OpenSSL implementation of it.

0

Let me start by saying, that a bit of guesswork is included in my answer. My best guess is that you issued 2 leaf certs and that one cert's issuer points to the other and the other way around, causing the loop.

I didn't try to reproduce your issue myself, but did play with cross signing. The LE site (Cross Signing by LE) and your hints, made me succeed in issuing and using cross signed certs. My objective was not CA root resilience but CA root roll-over. If your role is CA, it's basically not much different from what you tried to achieve. Critical factors are:

  • The Subject field must be identical (see above too)
  • The keys must be identical (see above too)
  • The certs must have a different issuer and 1 can be self-signed, like my application

Partly like the LE link, I created a cross signed Intermediate cert and one new root cert. A permanent Intermediate cert (PATHLEN:0) is signed by one of the 2 cross signed certs, unimportant which one, because the subject and keys are identical. Hint: reuse the CSR of the to-be cross certs for both, so the Subject can't be wrong. On the cross signed (temp.) Intermediate cert, I set the PATHLEN to 1 (can't be 0!)

To make it very clear:

  • Path 1 (old root): Leaf cert, perm. Intermediate cert, temp. Intermediate cert, 'old' root cert
  • Path 2 (new root): Leaf cert, perm. Intermediate cert, 'new' root cert

You can play with SAN and start/end dates what you like. The Intermediate cert (temp or roll-over) in the 'old' root path has 5 years validity, the 'new' root 10 years. After importing the 'new' root cert, the shorter (4 → 3) path was immediately used by Firefox. In my case you need to load 3 certs on the web-server: leaf cert, perm. intermediate cert, temp. intermediate ('old' root/temp/roll-over) cert.

OpenSSL didn't disappoint me to test the leaf cert for a valid path. I used OpenSSL's verify tool with CAfile for the root in the path and untrusted for the used Intermediate cert(s). Both paths to the old and the new root could be verified this way.

As an end-user (non-CA), if you want to have resilience, it should work with 1 CSR to get (order) leaf certs from 2 CAs and load your web-server with those 2 certs chained with the Intermediate cert from the issuing CA. So 4 certs in total.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.