Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

X25519 certificates #6072

Closed
nickray opened this issue May 28, 2021 · 7 comments · Fixed by #6562
Closed

X25519 certificates #6072

nickray opened this issue May 28, 2021 · 7 comments · Fixed by #6562

Comments

@nickray
Copy link

nickray commented May 28, 2021

I'd like to equip entities with X25519 keys and certificates, so they can verify each others' identity as being inside my PKI hierarchy (Noise for IoT, kinda).

It turns out to be possible to do this with openssl using -force_pubkey (yes, lovely ^^):

# generate CSR with an auxiliary key, e.g. Ed255
openssl req -new -key tmp-ed255-privkey.pem -out ed255-signed.csr
# then sign this CSR, replacing the public key
openssl x509 -req -in ed255-signed.csr -CAkey ca-privkey.pem -CA ca-cert.pem -force_pubkey x255-pubkey.pem -out x255-cert.pem -CAcreateserial

Would implementing this potentially be in scope here? It would be a little hacky presumably :) But if that's acceptable, I could try and prepare a PR.

@nickray
Copy link
Author

nickray commented May 28, 2021

FWIW, simply allowing X25519PublicKey (and X448PublicKey) in cryptography.x509.CertificateBuilder.public_key does the trick for me.

@markokr
Copy link
Contributor

markokr commented Jul 5, 2021

Is there official standard/RFC for X25519 in X.509?

@nickray
Copy link
Author

nickray commented Jul 7, 2021

RFC 8410

@reaperhulk
Copy link
Member

This is both easier and harder now. Easier in that we now independently do signing and generate all the ASN.1 ourselves in rust. Harder in that to support this we'd need to expand the X25519/X448 APIs to support signing, which is a bit weird. I think if we're going to do this we need to be able to strongly articulate why in documentation. e.g. the normal model is ed25519 is for signing and x25519 is for kex, why would x25519 for signing be desirable (and if it's fine to use it, why ever use ed25519?).

@nickray
Copy link
Author

nickray commented Nov 7, 2021

I believe there is a misunderstanding.

First, there are no X25519 signatures in standard cryptography (and the pyca shouldn't invent them). There are ways to convert between Ed25519 and X25519 keys (since they're on a birationally equivalent curve), and it's probably OK to use one key for both signing and key exchange (there are some preprints on this), but also likely not a good idea (general principles are to separate identity/signing from key exchange, e.g. due to different lifecycles).

That's not what this issue is about though: It asks for the possibility of certifying an X25519 key exchange key. With a separate signing key of any type (RSA, Ed25519, ...).

Operationally, this "just' means putting the X25519 public key in the SPKI of the cert and signing over it with the signing key. It's useful for the usual reasons: extend a third party's trust in a signing key to the certified key exchange key. This may or may not be a niche use case (establishing secure channels via key exchange against a closed-universe of X25519 recipients) - it's definitely a legitimate use case, but I'd understand if pyca/cryptography prefers not so support it.

The openssl snippet at the top was maybe confusing: In openssl, there must always be a CSR. This is just how its API works, and not an intrinsic requirement about X.509 certificates. For certificates for signing keys, the CSR is possible, and done to prove that the certificate is awarded to someone holding the private key. However, creating a certificate should really (additionally or mainly) mean that the certifier somehow legitimises the public key in its certificates. As a CA, I don't just sign any CSR, I inspect the public key and check that I want to extend it a certificate (I also review the other parameters of the certificate such as key uses, validity, extensions, etc.).

Since there is precedent for non-signing keys in the openssl universe, the -force_pubkey flag was added as a hacky way to work around the "CSR only" API (some ancillary discussion can be found here: https://groups.google.com/g/mailing.openssl.users/c/1QuxCKPZ_-o). The snippet shows how to do this (use a fake Ed255 key to create a CSR and swap out the public key for the X255 key of interest ant certificate generation time), but this is not how things ideally should work.

I don't think pyca/cryptography needs to follow the openssl API. In an ideal (from my perspective) world, there would be an API to create certificates for any algorithm's public keys (with either requester or granter choice of other parameters such as key uses, validity, extensions etc.), and an optional (additional) API that supports CSRs à la openssl (for signing keys only), implemented in terms of the more general API.

Makes sense?

@reaperhulk
Copy link
Member

reaperhulk commented Nov 7, 2021

Yes, I was definitely not reading your request correctly, thank you for being willing to explain it so clearly!

This actually works with no issues in current main, with the sole exception that our CertificateBuilder blocks it via a runtime isinstance check. I'm going to send a PR shortly updating it to allow this, expanding the mypy types, and updating docs.

Edit: To clarify, this works in main because we recently finished converting our entire X.509 layer into pure Rust and we now use OpenSSL solely for the cryptographic operations (hashing, generating the signature bytes).

@nickray
Copy link
Author

nickray commented Nov 8, 2021

Very cool, thanks!

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 7, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Development

Successfully merging a pull request may close this issue.

3 participants