SSL cannot get local issuer certificate when querying Pebble server

Hello, I'm using Pebble v1.0.1 with a config that is to be found in test/config/pebble_config.json and has come with the default installation.

Pebble startup messages are:

pebble@v1.0.1$ pebble -config test/config/pebble-con
fig.json
Pebble 2024/12/26 09:42:46 Starting Pebble ACME serv
er
Pebble 2024/12/26 09:42:46 Generated new root issuer
 with serial 1c70556bc997af7c
Pebble 2024/12/26 09:42:47 Generated new intermediat
e issuer with serial 41444473f42e407e
Pebble 2024/12/26 09:42:47 Configured to reject 5% o
f good nonces
Pebble 2024/12/26 09:42:47 Listening on: 0.0.0.0:140
00
Pebble 2024/12/26 09:42:47 ACME directory available
at: https://0.0.0.0:14000/dir
Pebble 2024/12/26 09:42:47 Root CA certificate avail
able at: https://0.0.0.0:14000/root

My issue is I cannot make any requests using Certbot without getting SSL error "unable to get local issuer certificate".

I'm using a script to always obtain the fresh root CA via curl, redirect the output to a file and point the REQUESTS_CA_BUNDLE variable the complete path.

After googling I think I might be missing the intermediate CA certificate in the bundle file, however I cannot determine how to obtain it.

Its serial number is being mentioned during Pebble's startup but it does not seem to be published anywhere just like the root CA is.

"curl -k https://0.0.0.0:14000/intermediate" and "curl -k https://0.0.0.0:14000/intermediates/0" both return "404".

Any ideas, please?
greetings,
michal

Edit: Okay my bad didn't know most of that

No, they're not.

Pebble generates its own chain every time it starts up.

You need to use port 15000 for the certs:

https://localhost:15000/intermediates/0

According to the documentation on Github:

Weird that Pebble itself claims port 14000?

3 Likes

I think there's some confusion here about how Pebble operates.

Pebble indeed generates a fresh root and intermediate (multiple if configured to do so) upon startup. However, the HTTPS server where Pebble offers its ACME & management services on is not actually using a certificate signed by this root. Rather, it uses a preconfigured (static) root certificate for that, to make configuration of ACME clients easier (to avoid exactly things like "obtain fresh root via curl, redirect to file...".

The default certificate for the HTTPS server can be found here: pebble/test/certs/localhost/cert.pem at main · letsencrypt/pebble · GitHub

Note that the private key is also publicly available there, so only add this certificate to trust stores with care (& remove it after testing).


The roots and intermediates endpoint(s) Pebble provides (i.e. https://localhost:15000/roots/0) are meant to only be used if you want to fetch the root to validate the certificate chain returned by Pebble, once a certificate has been issued. It's not helpful if you just want to talk to Pebble.


PS: This is also explained in the README: GitHub - letsencrypt/pebble: A miniature version of Boulder, Pebble is a small RFC 8555 ACME test server not suited for a production certificate authority.

6 Likes

I thought that was the signing certificate :thinking:

From the readme at https://github.com/letsencrypt/pebble/tree/main/test/certs:

This directory contains a CA certificate (…) and a private key (…) that are used to issue a end-entity certificate (…)

At least, the above was what I interpreted as being the cert that signed all the certs issued..

However, the end of that sentence is:

(…) for the Pebble HTTPS server.

So with "end-entity cert" they mean just the cert for the HTTPS server, instead of "all the end-entity certs issued". My bad :slight_smile:

3 Likes

Pebble randomizes the issuing certificate, to make it very difficult to misuse Pebble as a production-CA.

By design Pebble will drop all of its state between invocations and will randomize keys/certificates used for issuance.

Exactly.

4 Likes

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