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

How to consistently hash a certificate #28

Closed
zaynetro opened this issue Mar 23, 2020 · 6 comments
Closed

How to consistently hash a certificate #28

zaynetro opened this issue Mar 23, 2020 · 6 comments
Labels
question Further information is requested

Comments

@zaynetro
Copy link

Hi! I don't know if this is the best place for questions. If not feel free to close this.

I am implementing TLS authentication between two peers. On each peer I generate a Certificate and serialize it to disk with cert.serialize_private_key_pem().

Later I exchange peers' certificates cert.serialize_der() and then use rustls for establishing TLS session.

Everything works out well. The problem I am having is that I want to generate a hash (unique peer ID) from public certificate and keep it the same for each peer on each run. I've noticed that every time I call cert.serialize_der() it generates a slightly different output.

It seems that underlying key pair's public key remains the same so I can consistently generate a hash on each peer but then when TLS session is established I would like each peer to generate hash again from rustls::Session::get_peer_certificates().

What am I missing? What should I use as an input for hash generation? Is KeyPair::public_key_der() a good candidate? If yes, how do get it from rustls::Session?

My issues are most likely due to the lack of knowledge about certificates and encryption in general.

@zaynetro
Copy link
Author

Sorry for a lot of text. Writing down the problem is bringing me closer to the solution.

On the second though shall I do this instead:

  1. Client and server generate Certificates; and store private key and certificate on disk.
  2. Client and server exchange their certificates from disk instead of reading private key (and deriving one?)
  3. Client and server store certificates and generate hashes
  4. Then when client initiates a TLS session it reuses its own certificate from disk instead of Certificate::serialize_der().

Am I reinventing the wheel here? Due to my lack of knowledge I am not sure if this is correct or I am trying to work around the fact that Certificate::serialize_der() produces different output each time.

@est31
Copy link
Member

est31 commented Mar 23, 2020

I've noticed that every time I call cert.serialize_der() it generates a slightly different output.

Every time you call that function, we basically generate a new certificate. For generation, certificates have to be signed, which involves a random component. That's part of the standard how signatures work, and it's why it's slightly different each time you call that function. So yeah the hash will be different each time.

Also note that you should NEVER have to send anyone's private keys anywhere. In modern versions of TLS, it's mandatory to derive session keys anyways. So you should keep the private key to the server/client.

What should I use as an input for hash generation? Is KeyPair::public_key_der() a good candidate? If yes, how do get it from rustls::Session?

It's not. What you want is called certificate fingerprint, which is a hash of the DER encoded certificate, not the key.

Anyways, what exactly do you want to do in the first place?

@est31 est31 added the question Further information is requested label Mar 23, 2020
@zaynetro
Copy link
Author

Thanks for your time!

I have a process that generates a certificate on the first run. On consecutive runs it reads generated certificate from disk to establish TLS session.

Before establishing the session I want to exchange public keys (certificate fingerprint?) and I want each peer to hash public certificate (certificate fingerprint) to generate a unique peer ID for later use.

The way I started doing it is:

  • Generate certificate with generate_simple_self_signed
  • Read certificate KeyPair::from_pem and then set it to CertificateParams to construct a Certificate (similar to webpki test)
  • Share certificate Certificate::serialize_der() with another peer
  • Establish TLS session (server side is similar but I add client's certificate to RootCertStore)
tls_config.set_single_client_cert(
    vec![rustls::Certificate(cert.serialize_der()?)],
    rustls::PrivateKey(cert.serialize_private_key_der()),
)

What you want is called certificate fingerprint, which is a hash of the DER encoded certificate

Does Certificate::serialize_der() return DER encoded certificate?

Given the flow should I save certificate fingerprint to disk the first time I generate it and later read and send it instead of calling Certificate::serialize_der()?

@est31
Copy link
Member

est31 commented Mar 23, 2020

You are using generate_simple_self_signed as well as from_params? That's not how you are supposed to use the API... Instead you should use CertificateParams::new.

Does Certificate::serialize_der() return DER encoded certificate?

Yes.

Given the flow should I save certificate fingerprint to disk the first time I generate it and later read and send it instead of calling Certificate::serialize_der()?

No just store the serialized der content instead of the fingerprint. Use that instead of anything else.

@zaynetro
Copy link
Author

No, I use generate_simple_self_signed to generate a certificate once and then I store it on the disk with cert.serialize_private_key_pem().

Then when I need the certificate I read it from disk with KeyPair::from_pem and then construct a Certificate from CertificateParams with key_pair set.

Do I understand you correctly that instead of reconstructing a Certificate from the file I should just reuse file contents directly?

@zaynetro
Copy link
Author

Alright. I think I figured it out.

Thanks a lot for the help! Do you know any user forums / chat rooms where I can discuss these topics?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants