Self-signed root certificate in Python ACME libary

Hello everyone,

I'm currently implementing my own ACME-based client and server for a university project, and I've generated my own root certificate to verify HTTPS requests. While attempting to send a new_account request, I was looking for a way to pass my generated root certificate to the client in order to verify the server's certificate. However, I noticed that the verify_ssl parameter in the ClientNetwork class expects a boolean value.

The issue is that this parameter is only passed as an argument to the request method of the session library, and the session documentation states that the verify parameter can be either a boolean or a string if you want to use your own certificate chain.

Am I overlooking something, or is there a type mismatch in the constructor of the ClientNetwork class?

Regards,
Luca

The request to the Let's Encrypt API server is validated using the cert and chain you get back from the LE server. Which, today, means your ACME Client needs to validate it trusts the ISRG Root X1 CA root. Technically, you don't have to validate that cert but you definitely should to ensure you are talking to the actual LE API server. This is the true|false option you see in that call. Setting 'false' is very poor practice.

For HTTP Challenges, the Let's Encrypt Validation servers will make HTTP requests to the server indicated by the IP in the public DNS. No cert is involved on your server unless you redirect the HTTP request to HTTPS. The LE server will follow the redirect but does not validate the cert your server showed it. It is fine to use a self-signed cert if you wish.

I say all this just to get clarity on exactly which of these "flows" you need your "generated root certificate" for. Can you explain in more detail?

Perhaps this reference is also helpful: Challenge Types - Let's Encrypt

4 Likes

Hi @lucagebhardt and welcome to the community,

firstly, there are various ACME client implementations out there. It wasn't obvious to me which one you were using at first, but based on the description, I'm presuming that you're working with certbot/acme for the client.

Yes, this seems correct. Request supports to either turn off TLS server certificate validation completely (by setting this value to false), or to specify a collection of trusted certificates (a "bundle" in request's terminology). certbot/acme only seems to support the simpler use case, where validation is completely skipped.

For initial development, you could just set verify_ssl to false - you don't really need it for local client to server tests. If you do want TLS certificate validation with custom certs, note that you can also override the default CA bundle used by request externally.

4 Likes

Hey, thank you for your anwser.

I definitely want to check the certificates! But for the mentioned project, I need to implement my own ACME server and client. I generate my own root certificate, which I use to sign the certificate used by the web server implementation that handles requests such as new_account. To validate the certificate used by the server, I need the option to pass a root certificate to my client implementation. Just to clarify, it’s for a small project in a local lab environment, and I’m referring to the Python classes in this file: certbot/acme/acme/client.py at main · certbot/certbot · GitHub.

1 Like

@Nummer378 @MikeMcQ thank you very much for your quick and helpful answers!

3 Likes

Assuming you are allowed to, it may be easier to first build a client against an ACME server like Pebble (GitHub - letsencrypt/pebble: A miniature version of Boulder, Pebble is a small RFC 8555 ACME test server not suited for a production certificate authority.), then replace the server.

Certbot uses the requests library to communicate with acme servers - GitHub - psf/requests: A simple, yet elegant, HTTP library.

Requests uses the certifi package - a port of the mozilla trust store - as it's trust store - GitHub - certifi/python-certifi: (Python Distribution) A carefully curated collection of Root Certificates for validating the trustworthiness of SSL certificates while verifying the identity of TLS hosts.

You can override the trust store by setting an environment variable DEFAULT_CA_BUNDLE_PATH. See here:
https://requests.readthedocs.io/en/latest/user/advanced/

You can also have some test code that just iterates over a "fullchain" (your signed leaf, the server's intermediates and roots), ensuring the issuers match and certs were signed by one another.

I have some code that does that here:

I need to redo the new Cryptography code; it was actually easier to do in pyopenssl, but that library is essentially deprecated in favor of Cryptography.

7 Likes