Skip to content

Nonce reuse across requests → server returns badNonce #47

@rumfellow

Description

@rumfellow

Bug Overview

The client correctly fetches a nonce, then successfully creates an account and an order. On the next request to the authorization URL, the client reuses a prior nonce (identical JWS protected header as previous request), and the server responds with urn:ietf:params:acme:error:badNonce.

Expected Behavior

The client correctly fetches a nonce, then successfully creates an account and an order. On the next request to the authorization URL, the client reuses a prior nonce (identical JWS protected header as previous request), and the server responds with urn:ietf:params:acme:error:badNonce.

Steps to Reproduce the Bug

Use nginx-acme 0.1.1 with adapted example config against Hashicorp pki vault with ACME enabled.
vhost config:

resolver  172.22.30.39;

acme_issuer example {
    uri         https://vault/v1/muac-pki/roles/muac-pki-configuration/acme/directory;
    contact     [email protected];
    state_path  /var/cache/nginx/acme-example;
    accept_terms_of_service;
    ssl_verify off;
}

acme_shared_zone zone=ngx_acme_shared:1M;

server {
    listen 443 ssl;
    server_name  requestor.me;

    acme_certificate example key=rsa:4096;

    ssl_certificate       $acme_certificate;
    ssl_certificate_key   $acme_certificate_key;

    # do not parse the certificate on each request
    ssl_certificate_cache max=2;
}

server {
    # listener on port 80 is required to process ACME HTTP-01 challenges
    listen 80;

    location / {
        return 404;
    }
}

Environment Details

Client VM: RHEL 9.6 5.14.0-570.24.1.el9_6.x86_64
Client: nginx-acme/0.1.1 on nginx/1.29.1
ACME server: Hashicorp Vault OSS v1.16.1 (6b5986790d7748100de77f7f127119c4a0f78946)
Nginx <-> Vault direct connection, no proxying
Certbot can request certificate successfully

Additional Context

The MITM intercept (mitmproxy, transparent) details:

1) Get fresh nonce

Request

2025-09-03 10:22:36
GET https://vault/v1/muac-pki/roles/muac-pki-configuration/acme/new-nonce

Response 204 No Content
Headers:

Replay-Nonce: dmF1bHQw52bkRgQDO_iPZsGKa1tK11lb3trMp1E8SX9hrO83WtpQMcQ-zb6XMg   ;  (Nonce A)
Link: <https://vault/v1/muac-pki/roles/muac-pki-configuration/acme/directory>; rel="index"

2) Create account (uses Nonce A)
Request

POST https://vault/v1/muac-pki/roles/muac-pki-configuration/acme/new-account
Content-Type: application/jose+json

Body

{
  "payload": "eyJjb250YWN0IjpbIm1haWx0bzphZG1pbi..."],
  "protected": "eyJhbGciOiJFUzI1NiIsIm5vbmNlIjoiZG1GMWJIUXc1MmJrUmdRRE9faVBac0dLYTF0SzExbGIzdHJNcDFFOFNYOWhyTzgzV3RwUU1jUS16YjZYTWciLCJ1cmwiOiJodHRwczovL3ZhdWx0L.../YWNtZS9uZXctYWNjb3VudCIsImp3ayI6eyJjcnYiOiJQLTI1NiIsImt0eSI6IkVDIiwieCI6IjdKY25ESkp6ZDA4LUhmQTJXNlFOeGdMTzNpUks3R1NRYnJTQVdqSTkwdGsiLCJ5IjoiNmp6S3JTMTJ4T2lwUkR1MFlTOVFFdmxZUXg3S3dLTms0c2w5RUxxSFJhRSJ9fQ",
  "signature": "roYvvNxOkwrA-6sH...z4YMmQ"
}

Response 200 OK
Headers (selected):

Replay-Nonce: dmF1bHQwwfFNcP9wK-8kFdqWdmEnuPEDO1PZ6IOB3GTeHDv57Uv5cXhGcCwbeA   ;  (Nonce B)
Location: https://vault/v1/muac-pki/roles/muac-pki-configuration/acme/account/bc869801-4d57-d886-593d-ee268a62372f

Body

{
  "contact": ["mailto:[email protected]"],
  "orders": "https://vault/v1/.../account/bc869801-.../orders",
  "status": "valid"
}

3) Create new order (should use Nonce B; server returns Nonce C)
Request

POST https://vault/v1/muac-pki/roles/muac-pki-configuration/acme/new-order
Content-Type: application/jose+json

Body

{
  "payload": "eyJpZGVudGlmaWVycyI6W3sidHlwZSI6ImRucyIsInZhbHVlIjoicmVxdWVzdG9yIn1dfQ==",
  "protected": "eyJhbGciOiJFUzI1NiIsIm5vbmNlIjoiZG1GMWJIUXd3ZkZOY1A5d0stOGtGZHFXZG1FbnVQRURPMVBaNklPQjNHVGVIRHY1N1V2NWNYaEdjQ3diZUEiLCJ1cmwiOiJodHRwczovL3ZhdWx0L3YxL211YWMtcGtpL3JvbGVzL211YWMtcGtpLWNvbmZpZ3VyYXRpb24vYWNtZS9uZXctb3JkZXIiLCJraWQiOiJodHRwczovL3ZhdWx0L3YxL211YWMtcGtpL3JvbGVzL211YWMtcGtpLWNvbmZpZ3VyYXRpb24vYWNtZS9hY2NvdW50L2JjODY5ODAxLTRkNTctZDg4Ni01OTNkLWVlMjY4YTYyMzcyZiJ9",
  "signature": "rUVZgoe1ae1N5Gw0N1RxOpwi...XWIUmPg"
}

Response 201 Created
Headers (selected):

Replay-Nonce: dmF1bHQwlJ9CxxdvWuIbtDA8T0NhxmEbH0i9ZgVZvRf8sx0X1beF3Lw5OYuJ4w   ;  (Nonce C)
Location: https://vault/v1/.../acme/order/895107f9-fd75-0808-a098-739d34a4d08d

Body

{
  "authorizations": ["https://vault/v1/.../acme/authorization/988040e0-f976-a36c-8eba-aad7e55e4254"],
  "expires": "2025-09-04T08:22:37Z",
  "finalize": "https://vault/v1/.../acme/order/895107f9-fd75-0808-a098-739d34a4d08d/finalize",
  "identifiers": [{ "type": "dns", "value": "requestor" }],
  "status": "pending"
}

4) Fetch authorization (client reuses prior JWS protected → badNonce)
Request
POST https://vault/v1/.../acme/authorization/988040e0-f976-a36c-8eba-aad7e55e4254 Content-Type: application/jose+json

Body shows identical protected value as in step 3 (nonce reused):

{
  "payload": "",
  "protected": "eyJhbGciOiJFUzI1NiIsIm5vbmNlIjoiZG1GMWJIUXd3ZkZOY1A5d0stOGtGZHFXZG1FbnVQRURPMVBaNklPQjNHVGVIRHY1N1V2NWNYaEdjQ3diZUEiLCJ1cmwiOiJodHRwczovL3ZhdWx0L3YxL211YWMtcGtpL3JvbGVzL211YWMtcGtpLWNvbmZpZ3VyYXRpb24vYWNtZS9hdXRob3JpemF0aW9uLzk4ODA0MGUwLWY5NzYtYTM2Yy04ZWJhLWFhZDdlNTVlNDI1NCIsImtpZCI6Imh0dHBzOi8vdmF1bHQvdjEvbXVhYy1wa2kvcm9sZXMvbXVhYy1wa2ktY29uZmlndXJhdGlvbi9hY21lL2FjY291bnQvYmM4Njk4MDEtNGQ1Ny1kODg2LTU5M2QtZWUyNjhhNjIzNzJmIn0",
  "signature": "ixdYppdlztOfiAXAP_RDpwmr...w6BUwg"
}

Response 400 Bad Request
Body:

{
  "type": "urn:ietf:params:acme:error:badNonce",
  "detail": "invalid or reused nonce: The client sent an unacceptable anti-replay nonce",
  "subproblems": null
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions