C2SP / x509-limbo

A suite of testvectors for X.509 certificate path validation and tools for building them
https://x509-limbo.com
Apache License 2.0
38 stars 4 forks source link

RFE - Expected path in limbo.json #195

Open cipherboy opened 6 months ago

cipherboy commented 6 months ago

Browsing the JSON, expected_peer_name is given to help the harness validate the peer's identity for each test case. But AFAICT, no indication of expected path exists outside of the human-readable description field.

However, it'd be great to have allowed (or denied, when simpler) chain path(s) annotated for the test suite. E.g., in the negative test case pathlen::intermediate-violates-pathlen-0, perhaps this'd be:

"denied_paths": [
  [
    "CN=x509-limbo-root",
    "OU=108858597233759013321958503749681591474467573902,CN=x509-limbo-intermediate-pathlen-0",
    "OU=101602283156362821002694322459160944963902715535,CN=x509-limbo-intermediate-pathlen-0",
    "CN=example.com"
  ]
]

Or maybe using references and indices (trusted_certs:0 -> untrusted_intermediates:0 -> untrusted_intermediates:1 -> peer_certificate) if that is simpler than Subjects.

This would help for unit testing chain building frameworks. For the subset of checks applicable to just the path building code, these could be extracted from the JSON and positively asserted against. And it helps confirms that the client accepted it for one of the right reasons. For example, in the Go harness:

https://github.com/C2SP/x509-limbo/blob/471656dc73cedf02eaac82c45d7bd874d097dfc9/harness/gocryptox509/main.go#L208-L209

...the contents of chain are left unvalidated.


Personally, my motivation also comes from work on the CA side: in cases where CA software contains multiple roots & ICAs, e.g., due to rotation, they may opt to support automatic chain building if multiple ICAs are loaded into a single instance. This is the case in Vault's/OpenBao's PKI Secrets Engine's chain building code. It is not necessarily meant to be strictly browser-grade RFC 5280/X.509/CA-BF compliant, most notably because it is computed prior to having a concrete leaf and because many attributes are left to the browser or leaf issuance code to enforce. And, as far as I know, nobody is running it as a web-grade PKI, especially without CT. :-D

However, it'd still be great to be able to take a subset of these tests, chop off the leaf, and validate the internal code constructs possible valid CA paths without any obviously invalid ones.


Professionally, feel free to ping me if you have questions on the Bouncy Castle modules. :-) (Are you leaning towards Java or C# or both?).

Thanks!

woodruffw commented 6 months ago

Thank you for this thoughtful RFE!

Yeah, I think this is something we should do. I think doing it with just allowed_paths would generalize fine, since we could do allowed_paths: [] when no paths should construct.

One hiccup here is in the references we choose to use for the path members, as you've mentioned. We could use the cert subjects, but we may want to add some ambiguous/subject confusion cases in the future. Similarly, we currently generate all certs on the fly, so the SN and other bits currently aren't stable between generations, unfortunately (this is my mistake 🙂). One idea: we could use sha256(DER) for each cert, since that'll be stable for any given unique cert assuming correct canonical DER encoding. But maybe we should fix #8 first.

(Another thing: ideally we'd generate this info in the same "pass" as the testcase itself, rather than having to manually mark each testcases' valid paths. This might require some rearchitecting.)

Bottom line: this is something I'd like to see, but I think it has a few changes/design shifts above it in the stack to make it tractable. But those are themselves doable and things we already have slated to do!

Professionally, feel free to ping me if you have questions on the Bouncy Castle modules. :-) (Are you leaning towards Java or C# or both?).

Thank you, I will! Ideally we'll do both, over time.

Longer term, it'd be fantastic if Bouncy Castle were to integrate the x509-limbo testcases directly -- the two modules could do something similar to what PyCA Cryptography does, which is skip testcases/entire features that are intentionally unsupported.