Shortlived certificate stuck as processing

Hi,

I was trying to add support for shortlived certificate to my perl acme client.

I experience a bug I don't understand while trying to generate a certificate for :
vpn.aoihime.eu
aurae.aoihime.eu
144.76.27.210
2a01:4f8:191:1405::

Finalize uri :
https://acme-staging-v02.api.letsencrypt.org/acme/finalize/233932/27051653744

All authorizations seems to have passed, but the finalize request still fail with a processing status instead of issuing the certificate or an invalid state.

If I retry the processes, I get a 403 forbidden...

Finalize request content :

{
    'identifiers' => [
    {
        'type' => 'dns',
        'value' => 'aurae.aoihime.eu'
    },
    {
        'value' => 'vpn.aoihime.eu',
        'type' => 'dns'
    },
    {
        'type' => 'ip',
        'value' => '144.76.27.210'
    },
    {
        'value' => '2a01:4f8:191:1405::',
        'type' => 'ip'
    }
    ],
    'status' => 'processing',
    'authorizations' => [
        'https://acme-staging-v02.api.letsencrypt.org/acme/authz/233932/19191772074',
        'https://acme-staging-v02.api.letsencrypt.org/acme/authz/233932/19191772084',
        'https://acme-staging-v02.api.letsencrypt.org/acme/authz/233932/19191772094',
        'https://acme-staging-v02.api.letsencrypt.org/acme/authz/233932/19191772104'
    ],
    'profile' => 'shortlived',
    'finalize' => 'https://acme-staging-v02.api.letsencrypt.org/acme/finalize/233932/27051653744',
    'expires' => '2025-09-03T18:11:30Z'
};

Is their a problem on letsencrypt side ? Certificates with IP seemed to be supported as of now, no ?

Subsequent requests :
POST https://acme-staging-v02.api.letsencrypt.org/acme/finalize/233932/27051653744 failed: 403 Forbidden at /usr/bin/acme line 487.
POST https://acme-staging-v02.api.letsencrypt.org/acme/finalize/233932/27051653744 failed: 400 Bad Request at /usr/bin/acme line 487.
POST https://acme-staging-v02.api.letsencrypt.org/acme/finalize/233932/27051653744 failed: 400 Bad Request at /usr/bin/acme line 487.

Payload :
{
'profile' => 'shortlived',
'identifiers' => [
{
'type' => 'dns',
'value' => 'vpn.aoihime.eu'
},
{
'type' => 'ip',
'value' => '144.76.27.210'
},
{
'type' => 'ip',
'value' => '2a01:4f8:191:1405::'
},
{
'type' => 'dns',
'value' => 'aurae.aoihime.eu'
},
{
'type' => 'dns',
'value' => 'vpn.aoihime.eu'
}
]
}

Why do you think that "processing" is a failure? Processing means that it's in progress, and you need to poll the order until it becomes "valid" or "invalid". Look at the flowcharts in RFC 8555 section 7.1.6.

The order moves to the "processing" state after the client submits a request to the order's "finalize" URL and the CA begins the issuance process for the certificate. Once the certificate is issued, the order enters the "valid" state. If an error occurs at any of these stages, the order moves to the "invalid" state.

You may want to look at this announcement. They don't have asynchronous finalization in prod, but they may still have it on in staging:

3 Likes

Motivation was comming from the requirement of my vpn with a letsencrypt certificate for ease of use to circuvent the fucking age verification laws and censorship in france...

Thanks, will look into it, maybe I need to change something in the order polling as the behaviour changed...

Small question, when I issue my newOrder if it fails in status = processing, what should I do ?

I poll already until every challenge is flagged as valid.

Which uri should I poll to know the status of my order ?
(finalize issue a 403)

Should I poll on newOrder uri with same payload until I get a status=ready instead of processing ?

Again, I don't know why you say it "fails", you're getting a 200 OK and the "processing" means that it's working as expected.

Look at page 48 of RFC 8555, which lists what you should do depending on the status.

The order URI. It's in the "Location" header of the finalize request, and I think you would have received in response to the new order request as well. Make sure you're using a POST-as-GET request for it.

3 Likes

Getting a 200 OK response with a processing response is confusing.

It may have been smarter to send a 100 Continue, 102 Processing or 103 Early Hints ?

I think the implementation is strange, the client issue the newOrder, get a 200 OK, then check that all authorizations have passed, then has to POST-as-GET on Location header hidden in the newOrder request...

Maybe it's too late to change the behaviour, but it's far from the KISS and stateless webservice logic.

Developping the acme client is hard, because of the processing/ready state that can't be determisticly reproduced.

Thank's for your help, I hope I will succeed.

I'll definitely agree that the ACME protocol seems more convoluted than it needs to be. It's designed to be extensible and work across a lot of different server and client implementations, but there weren't all that many different implementations to start with as they were making it. Things like that posting an empty body and posting a {} body do different things is also a "gotcha" for a lot of implementors. It has all the advantages and disadvantages of being designed by committee. :slight_smile:

But, for better or worse, it's the standard. And that text on page 48 says that with a 200 OK response, just what should be done for each of the 5 possible status responses.

Also, I highly recommend testing against more than just Let's Encrypt's systems. Other CAs sometimes do things just slightly differently, and there's Pebble as well which is designed for testing.

5 Likes