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

If that's your issue, maybe you should change programming languages.

I was responding to a thread that asked how Let’s Encrypt could make developer’s lives easier. I shared my own experience and my own recommendation. Changing programming languages and using a 1MB external tool instead of a 1MB library doesn’t solve the issue I’m attempting to address.

I believe I’ve said all I can on the matter so I’ll leave it here.

1 Like

Your JSON version of the CSR does not include proof that you are in possession of the private key for that public key. One of the main points of the CSR is to include that proof (by signing the CSR with the private key for the public key it includes).

Of couse you could extend that JSON, but in the end you will end up with a complex thing that does a subset of what the CSR format does, but there is no existing library support for creating these things. Which in the end is forcing everyone to invest a lot more work. (Which isn't an issue for Big Tech, but for Small Tech and Small Web. Which is exactly what you wanted to avoid.)

Regarding the signature algorithm not supported: maybe you are using SHA-1, which has been deprecated for a looooooooooooooong time and finally got disabled recently? Rejecting SHA-1 CSRs and validation using TLS 1.0 / 1.1 URLs


Thanks, it’s a 2048-bit SHA256 key so I don’t think that’s the problem (and I appreciate your help but I don’t want to hijack this thread with debugging my issue. I’ll open a separate one if I can’t figure it out today.) :slight_smile:

Nope, despite what my own comment says, the signature is apparently sha1. So, yeah, assuming that’s the issue. Thanks again.

PS. Pebble version 2.3.1 (which, as far as I can see is the latest release – Releases · letsencrypt/pebble · GitHub), is not catching this. Opened an issue here: Pebble should fail CSR requests signed using SHA-1 · Issue #384 · letsencrypt/pebble · GitHub

> openssl req -in test.csr -text -noout

Certificate Request:
        Version: 1 (0x0)
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus: …
                Exponent: 65537 (0x10001)
            Requested Extensions:
                X509v3 Subject Alternative Name: 
                TLS Feature: 
    Signature Algorithm: sha1WithRSAEncryption
    Signature Value: …

Yeah, I suspect that one of the biggest things Let's Encrypt could do to make client dev easier is to ensure that there are clear test cases for the ACME spec (or at least for their implementation of it), including making changes in Pebble before even putting them into Boulder staging.


I'm not sure if this would make client dev easier, but it would definitely make it better. So +1 on this.

I think it would be great if there should be a list/repo/etc of official test scenarios that a client should implement in their test suite, and pass or otherwise gracefully handle.

The issues I encountered when developing a client:

  • The spec is not clear on certain things.
  • There were undocumented divergencies between Boulder and Pebble.

The issues in the ecosystem I noticed:

  • Most clients DID NOT utilize any testing. Not everyone can do CI testing, that's fine - but so many clients have ZERO test suites. no unit tests. no integrated tests. nothing. imho, that's terrifying.

Yes, in the early days of the ACME protocol I seem to remember that we did want to potentially get rid of ASN.1—I think I suggested that we could invent our own totally new way of cryptographically binding subject keys to requests!—but someone¹ pointed out that many people would have CSRs generated externally, or the ability to generate CSRs externally (e.g. from an embedded device, or from a hosting provider, or from a CDN). As a result, ACME ended up using CSRs inside the protocol and explicitly not requiring any other proof of possession of the subject key. (ACME does provide a cryptographic binding between the ACME request and the CSR, though.)

Having CSRs in the protocol is annoying and possibly unfortunate, but it dramatically increased compatibility of ACME CA services compared to the alternative.

External CSRs aren't the best from an automation point of view, so that's a tension (like, if the subject key is being generated outside of the ACME client itself, you have to find a way to cause the CSR to be generated at the appropriate time, and a way to copy it into the machine running the ACME client!), but they do have potentially cool security properties. For example, you could generate a keypair in an HSM or something and then use a separate machine to obtain a certificate referring to that keypair, without ever exporting it anywhere, and without requiring the ACME client to be trusted with any access to the private key material. Reducing trust in the ACME client is probably a desirable thing in some settings!

¹ Edit: I think the Mozilla contributors had a whole exercise of gathering requirements, or at least preferences, from various web hosts somehow, which I don't think I was privy to. They definitely ended up having a lot to say about what different certificate subscriber end-users would want out of ACME!


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:


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.