What could Let’s Encrypt do to make client dev easier?

in resent mozilla store policy they concoluded it's csr itself wan't enough to confirm subscriber did possessed its private key and CA MUST NOT assume so, because of that it would not cause much difference what ca can do with key revocation request with or without CSR. if we require to verify possition of private key we'd need to add a challange to sign a nonce with that keypair.


@orangepizza The only thing in that policy regarding CSR and private keys is specifically for revocation, which makes sense, as CSRs are considered rather public (e.g. here on the Community we regularly ask for CSRs if there is an issue with it).


well, there wasn't any requirement for CA to check subscriber's possession of private key (CA/B BR 3.2.1 is empty) so that's only place policies care about private key possession for TLS leaf certificate


And in fact, in the past a CA has issued a certificate without requiring the corresponding private key to be under their subscriber's control (as CSRs aren't actually required to be used by the specs), and it wasn't considered an "incident" by Mozilla, though it's certainly weird.



I’ve opened a PR to reject SHA-1 CSRs in pebble, aligning with boulder


So is the Private Key not even required to generate the CSR? I never really thought about this before, but it does make sense that only the Public Key is used with the CSR.


CSRs are signed, so the private key is needed to compute that signature. Let’s Encrypt requires and validates that signature. Not all CAs use CSRs, or check CSR signatures, and the Baseline Requirements don’t require that.

Pebble doesn’t currently check signatures on CSRs, though my pull request changes that.


Is it possible to sign a CSR with a different key than the embedded public key?


That would be an invalid signature and wouldn't validate. Signatures need to be checked against a public key, and that public key is in the CSR -- there's only the one.


Just for clarity for future readers, a certificate signing request (CSR) is self-signed in the same way that a (true) root certificate is self-signed. When something wants to verify the signature on either, it need look no further than the public key included alongside the signature.


According to whom? We've already established earlier in this thread that CAs in general, the CA/B Forum BR and the ACME protocol don't have such restrictions.

I'm just wondering if it's technically possible to sign CSR with a different key :slight_smile:

1 Like

Both the public key and the signature are in the CSR. If you signed with a different key than the one in the CSR, that signature will fail to validate cryptographically. In fact that would be the easiest way to generate an invalid signature. Pebble today (without my PR) would accept such a CSR as it doesn’t check the signature (yet).


Sure. I mean you could even fill the signature with 0xDEADBEEF or random numbers or omit it entirely. Some of those options might not parse correctly and certainly won't validate, but it's technically possible. :grin:


Thanks for the clarification. Now I understand the thread referenced above: Digicert was essentially creating an unsigned CSR based on an existing certificate/public-key to re-issue a certificate.


I'm not sure Digicert even created a CSR: why would they? Let's Encrypt also doesn't actually use the CSR directly: it just checks for signature validity and just extracts the info from the CSR.

Digicert could easily just pull the info from the existing cert without ever using a CSR.

Although, thinking about what I said above a little bit more: HSM could have restictions about what they'd accept to sign. Maybe HSMs only accept CSRs?


Generally not; they expose a low-level signing primitive like "Compute a P-384 signature over this blob of bytes". However, CSRs are very widely supported as a defacto standard so the pipeline of CSR -> Certificate + HSM signature is widely supported by basically every piece of Certificate Authority software.


Ah OK, so that would mean it isn't indeed necessary to use a CSR in the whole certificate issuance pipeline entirely, thanks!

Including Boulder? Hmm, I'm not familiar enough with Boulder to know, perhaps it does generate a new CSR..

Anyway, ASN.1. is here to stay, that's the bottom line I guess :stuck_out_tongue:


I'm not sure they would have actually created an RFC compliant CSR either. That's why I wrote "essentially creating an unsigned CSR" – whatever actions were in their pipeline had the same substance, contents, and effects that would have been conveyed with an unsigned CSR.


Actually, that stuff is all in the "Implemenation Details" document! I only know this because I wrote that document ;).

Extending this idea, I think having a checklist of best practices vs common pitfalls would be great.

In my experience, it is exceedingly rare for people to develop a client based on the RFC. The first clients/proof-of-concept will probably be built as the RFC is developed. The majority of subsequent clients will be developed by forking, rewriting, or lifting code. Some developers will never even look at the RFC. This isn't specific to ACME, but a trend I've noticed across all implementations of RFCs/specs.

When ISRG first cycled intermediates, many clients broke. A shocking large number of clients were built with the chains/intermediates hardcoded - someone did it first, it worked, and then copy upon copy this persisted.

I don't think this needs to be a longform article, just a series of details that developers can check-off as they continue to develop.

Also, a way to configure Pebble to act like Boulder would be great. I ended up writing a "fake server" that could step though the Boulder process when I was first developing a client. I value that Pebble is great for ensuring compliance and running advanced tests... but if one writes TO pebble and does not fully understand the divergences, they are guaranteed to develop a client that is not compatible with Boulder. A simple way to test against Boulder would do a lot of good.


I would never! No... wait... I did. :grin:

https://gethttpsforfree.com was the initial basis of my client lines. Granted I went and wrote my own DER, CSR, and key decoders and referenced the RFC as I went along.

That's what I used the staging environment for.