voltone / x509

Elixir package for working with X.509 certificates, Certificate Signing Requests (CSRs), Certificate Revocation Lists (CRLs) and RSA/ECC key pairs
BSD 3-Clause "New" or "Revised" License
119 stars 27 forks source link

Function that returns the version of a certificate #25

Closed tanguilp closed 5 years ago

tanguilp commented 5 years ago

Provide with a function that returns the version of a certificate (X509.Certificate.version/1 ?)

Rationale: I'm working with certificates and need to check things as the types of their public keys, values of extensions, value of the subject, etc. X509 provides with all the needed functions in 509.Certificate, except for the simple certificate version. I've found no other way to get it that to pattern match the :OTPCertificate & :OTPTBSCertificate structures (since importing Erlang records is overkill).

voltone commented 5 years ago

Ok, I have personally never had a need to check the version of a certificate (I believe the vast majority of valid certificates out there are v3), but I don't mind adding such a function. Would you expect it to return the atom :v3 or the integer 3?

tanguilp commented 5 years ago

Agree this is uncommon, I had to check cert version when implementing FIDO2 (example: https://www.w3.org/TR/2019/PR-webauthn-20190117/#packed-attestation-cert-requirements). I'd expect the :v3-like atoms I guess.

tanguilp commented 5 years ago

A bit more of context here: I needed this function when implementing WebAuthn (when verifying certificate it's stated that cert version should be checked, example: https://www.w3.org/TR/webauthn/#packed-attestation-cert-requirements).

I guess it's very uncommon, so still not sure it'd be relevant to add it. Besides here are the X509 certs functions I had to write by myself: https://github.com/tanguilp/wax/blob/master/lib/wax/utils/certificate.ex (You can note that the CN is retrieved in a ugly way, could X509 help with that?)

voltone commented 5 years ago

That spec requires a BasicConstraints extension to be present, which rules out any pre-v3 certificate formats anyway (which did not have the Extensions field). So it is probably superfluous to explicitly check for v3, but I can still add a function to fetch it.

As for the CN, I can imagine an API like Certificate.subject(cert, "CN"), which would extract the RDN and then call a function in RDNSequence to look up the specified attribute. Since attributes may appear more than once (in particular "OU") it would have to return a list of values.

BTW, I'm planning a major rewrite of the library, extracting all the lower level stuff to an Erlang lib, and making the Elixir API about working with :public_key records in an Elixir-friendly way. Now I just need to find the time to work on it...

tanguilp commented 5 years ago

Good idea for getting the subject components, would be helpful.

One more thing which came to my mind: I sometimes needed to retrieve the algorithm and not only the public key (in Wax, or here: https://github.com/tanguilp/apisex_auth_mtls/blob/master/lib/apisex_auth_mtls.ex#L344) so as to compare it or to then use :public_key.verify/4. Basically, it's about getting the hash algorithm. Just to give you an idea of what can be needed when implementing such protocols. Still not sure whether it should be included in X509 (which proved very useful to me - thanks!). Also I'm looking for Elixir programmers with a security background to review my WebAuthn & MTLS libs so... but it seems you're busy enough :)

voltone commented 5 years ago

I started to work on the API to retrieve Subject/Issuer attributes.

As for the code you linked to, it does not use the signing or hashing algorithm, it just extracts the SPKI and uses that for matching selfsigned certificates against a whitelist. SPKI is just a wrapper for serializing keys with any necessary metadata needed for deserialization. Matching on the decoded public key would seem easier to me.

Normally it is not necessary for an application to be aware of the hashing or signing algorithm used within a certificate: it should only be used by :public_key to verify the certificate itself (and the issuing chain). If the verification is successful, the public key can be used by the application with any suitable algorithms (within the constraints set by KeyUsage and ExtendedKeyUsage).

voltone commented 5 years ago

Added version/1, subject/2 and issuer/2 in v0.5.2