# Self-signed root certificate in Python ACME libary

**URL:** <https://community.letsencrypt.org/t/self-signed-root-certificate-in-python-acme-libary/231705>\
**Category:** Client dev\
**Created:** [January 8, 2025, 1:53pm UTC](https://community.letsencrypt.org/t/self-signed-root-certificate-in-python-acme-libary/231705 "2025-01-08T13:53:01Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![lucagebhardt](https://sea3.discourse-cdn.com/letsencrypt/user_avatar/community.letsencrypt.org/lucagebhardt/32/85041_2.png) [@lucagebhardt](https://community.letsencrypt.org/u/lucagebhardt)\
**Post date:** [January 8, 2025, 1:53pm UTC](https://community.letsencrypt.org/t/self-signed-root-certificate-in-python-acme-libary/231705/1 "2025-01-08T13:53:01Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![MikeMcQ](https://sea3.discourse-cdn.com/letsencrypt/user_avatar/community.letsencrypt.org/mikemcq/32/52772_2.png) [@MikeMcQ](https://community.letsencrypt.org/u/MikeMcQ)\
**Post date:** [January 8, 2025, 2:06pm UTC](https://community.letsencrypt.org/t/self-signed-root-certificate-in-python-acme-libary/231705/2 "2025-01-08T14:06:53Z")

</div>

> [@lucagebhardt](#):
>
> 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.

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](https://letsencrypt.org/docs/challenge-types/)

---

<div class="post-metadata">

**Author:** ![Nummer378](https://sea3.discourse-cdn.com/letsencrypt/user_avatar/community.letsencrypt.org/nummer378/32/49862_2.png) [@Nummer378](https://community.letsencrypt.org/u/Nummer378)\
**Post date:** [January 8, 2025, 2:15pm UTC](https://community.letsencrypt.org/t/self-signed-root-certificate-in-python-acme-libary/231705/3 "2025-01-08T14:15:34Z")

</div>

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.

> [@lucagebhardt](#):
>
> 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.

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](https://stackoverflow.com/a/42982144/14694855).

---

<div class="post-metadata">

**Author:** ![lucagebhardt](https://sea3.discourse-cdn.com/letsencrypt/user_avatar/community.letsencrypt.org/lucagebhardt/32/85041_2.png) [@lucagebhardt](https://community.letsencrypt.org/u/lucagebhardt)\
**Post date:** [January 8, 2025, 2:20pm UTC](https://community.letsencrypt.org/t/self-signed-root-certificate-in-python-acme-libary/231705/4 "2025-01-08T14:20:24Z")

</div>

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](https://github.com/certbot/certbot/blob/main/acme/acme/client.py).

---

<div class="post-metadata">

**Author:** ![lucagebhardt](https://sea3.discourse-cdn.com/letsencrypt/user_avatar/community.letsencrypt.org/lucagebhardt/32/85041_2.png) [@lucagebhardt](https://community.letsencrypt.org/u/lucagebhardt)\
**Post date:** [January 8, 2025, 2:26pm UTC](https://community.letsencrypt.org/t/self-signed-root-certificate-in-python-acme-libary/231705/5 "2025-01-08T14:26:51Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![jvanasco](https://sea3.discourse-cdn.com/letsencrypt/user_avatar/community.letsencrypt.org/jvanasco/32/55900_2.png) [@jvanasco](https://community.letsencrypt.org/u/jvanasco)\
**Post date:** [January 8, 2025, 4:14pm UTC](https://community.letsencrypt.org/t/self-signed-root-certificate-in-python-acme-libary/231705/6 "2025-01-08T16:14:28Z")

</div>

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.](https://github.com/letsencrypt/pebble)), then replace the server.

Certbot uses the `requests` library to communicate with acme servers - [GitHub - psf/requests: A simple, yet elegant, HTTP library.](https://github.com/psf/requests)

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.](https://github.com/certifi/python-certifi)

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/](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:

- [cert\_utils/src/cert\_utils/core.py at main · aptise/cert\_utils · GitHub](https://github.com/aptise/cert_utils/blob/main/src/cert_utils/core.py#L2196-L2463)  
and
- [cert\_utils/src/cert\_utils/compat/pyopenssl.py at main · aptise/cert\_utils · GitHub](https://github.com/aptise/cert_utils/blob/main/src/cert_utils/compat/pyopenssl.py)

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.

---

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/letsencrypt/original/3X/c/a/ca6c06ea1ea201324bba7048c6841ce60236468d.png) [@system](https://community.letsencrypt.org/u/system)\
**Post date:** [February 7, 2025, 4:14pm UTC](https://community.letsencrypt.org/t/self-signed-root-certificate-in-python-acme-libary/231705/7 "2025-02-07T16:14:33Z")

</div>

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.
