Trouble with ACME v1 endpoint

Hi,

I'm currently tring to add support for Buypass' ACME endpoints to the Ansible acme_certificate ACME client (https://docs.ansible.com/ansible/latest/modules/acme_certificate_module.html). I was successful with making ACME v2 support work (https://github.com/ansible/ansible/pull/60727), but I'm totally unsuccessful with the ACME v1 endpoints (both production and staging). Every time I try to use the new-reg endpoint, I get an urn:ietf:params:acme:error:malformed error with detail INVALID_JSON_JWS. Since the code works fine with Let's Encrypt's ACME v1 staging endpoint, I'm not really sure what I'm doing wrong.

 

Here's what I'm sending to https://api.test4.buypass.no/acme/new-reg via POST. Protected:

{
  "alg": "RS256",
  "jwk": {
    "e": "AQAB",
    "kty": "RSA",
    "n": "sy-niFwnwfJ4H-Z2yPpf2ww8kyepRK_uS1HWebVqjV_uoHYkEazaunfsHTIXnZpxs09_SLtByOCGdBibi04x5tyx9SMwJ-z9kEsBAlJD-a3vX5juJNLfn-tes86ulQnvJk8YrCI-W7GenZYWYgSC_f3rMdlvTsxt5Jb4Ck1yrLW12JBPmDwP2ttVaSwpWSkadsa2ESw0Cgw7asDkwoX8FVqgXPbvsmo_aCOasGYwiodsjCmWhVV9ovlSPWulkgMtHGSvMJJvWSBDTWinwhVtKkXQGcOFffjNnTHtYx_4Lqv5oK-SEyopqou8OiAtQtYhX5jTOqii5DnPbhEzFt-P4fRIXei1x98VFI6LPrxfV74H4Ws_Kp0wzW8XknDE-VAt18IsW7KkXmcvrMshZHAs3dhRetQYIe8SZGQGqjbm8aNz_Fwbqn5yD00bnM4vt824M_SYhQitTQxsSVpH62aduuw5TrJAXoVE96j0gfRz09Al9XL9L1zRA6QZ2jKYlKF-mlTa5EPCq510GDITxggqEgg8_C20iJizzOGUm1ftBOACGonK9IT8eojFe_WGXjGoVRmrE4tZJ8HPFXPU6-VLuLbhkAcJmtf8d1JWTmR2d0NBXF_w9alSTo_Q_O53ZXBITSNKo0jE8OMuQff9_n3y2CgmKm7HpNotHT5V1zjReZU"
  },
  "nonce": "ODhjMmM4NDgtZWQzMy00YjlmLWExMDYtMDc4ZjQ1ZTRjOGVm"
}

 Payload:

{
  "agreement": "https://api.test4.buypass.no/acme/terms/3361",
  "contact": [
    "mailto:<censored;decode payload below to find out>"
  ],
  "resource": "new-reg"
}

Resulting signed request:

{
  "header": {
    "alg": "RS256",
    "jwk": {
      "e": "AQAB",
      "kty": "RSA",
      "n": "sy-niFwnwfJ4H-Z2yPpf2ww8kyepRK_uS1HWebVqjV_uoHYkEazaunfsHTIXnZpxs09_SLtByOCGdBibi04x5tyx9SMwJ-z9kEsBAlJD-a3vX5juJNLfn-tes86ulQnvJk8YrCI-W7GenZYWYgSC_f3rMdlvTsxt5Jb4Ck1yrLW12JBPmDwP2ttVaSwpWSkadsa2ESw0Cgw7asDkwoX8FVqgXPbvsmo_aCOasGYwiodsjCmWhVV9ovlSPWulkgMtHGSvMJJvWSBDTWinwhVtKkXQGcOFffjNnTHtYx_4Lqv5oK-SEyopqou8OiAtQtYhX5jTOqii5DnPbhEzFt-P4fRIXei1x98VFI6LPrxfV74H4Ws_Kp0wzW8XknDE-VAt18IsW7KkXmcvrMshZHAs3dhRetQYIe8SZGQGqjbm8aNz_Fwbqn5yD00bnM4vt824M_SYhQitTQxsSVpH62aduuw5TrJAXoVE96j0gfRz09Al9XL9L1zRA6QZ2jKYlKF-mlTa5EPCq510GDITxggqEgg8_C20iJizzOGUm1ftBOACGonK9IT8eojFe_WGXjGoVRmrE4tZJ8HPFXPU6-VLuLbhkAcJmtf8d1JWTmR2d0NBXF_w9alSTo_Q_O53ZXBITSNKo0jE8OMuQff9_n3y2CgmKm7HpNotHT5V1zjReZU"
    }
  },
  "payload": "eyJyZXNvdXJjZSI6ICJuZXctcmVnIiwgImNvbnRhY3QiOiBbIm1haWx0bzpmZWxpeEBmb250ZWluLmRlIl0sICJhZ3JlZW1lbnQiOiAiaHR0cHM6Ly9hcGkudGVzdDQuYnV5cGFzcy5uby9hY21lL3Rlcm1zLzMzNjEifQ",
  "protected": "eyJhbGciOiAiUlMyNTYiLCAiandrIjogeyJrdHkiOiAiUlNBIiwgImUiOiAiQVFBQiIsICJuIjogInN5LW5pRndud2ZKNEgtWjJ5UHBmMnd3OGt5ZXBSS191UzFIV2ViVnFqVl91b0hZa0VhemF1bmZzSFRJWG5acHhzMDlfU0x0QnlPQ0dkQmliaTA0eDV0eXg5U013Si16OWtFc0JBbEpELWEzdlg1anVKTkxmbi10ZXM4NnVsUW52Sms4WXJDSS1XN0dlblpZV1lnU0NfZjNyTWRsdlRzeHQ1SmI0Q2sxeXJMVzEySkJQbUR3UDJ0dFZhU3dwV1NrYWRzYTJFU3cwQ2d3N2FzRGt3b1g4RlZxZ1hQYnZzbW9fYUNPYXNHWXdpb2RzakNtV2hWVjlvdmxTUFd1bGtnTXRIR1N2TUpKdldTQkRUV2lud2hWdEtrWFFHY09GZmZqTm5USHRZeF80THF2NW9LLVNFeW9wcW91OE9pQXRRdFloWDVqVE9xaWk1RG5QYmhFekZ0LVA0ZlJJWGVpMXg5OFZGSTZMUHJ4ZlY3NEg0V3NfS3Awd3pXOFhrbkRFLVZBdDE4SXNXN0trWG1jdnJNc2haSEFzM2RoUmV0UVlJZThTWkdRR3FqYm04YU56X0Z3YnFuNXlEMDBibk00dnQ4MjRNX1NZaFFpdFRReHNTVnBINjJhZHV1dzVUckpBWG9WRTk2ajBnZlJ6MDlBbDlYTDlMMXpSQTZRWjJqS1lsS0YtbWxUYTVFUENxNTEwR0RJVHhnZ3FFZ2c4X0MyMGlKaXp6T0dVbTFmdEJPQUNHb25LOUlUOGVvakZlX1dHWGpHb1ZSbXJFNHRaSjhIUEZYUFU2LVZMdUxiaGtBY0ptdGY4ZDFKV1RtUjJkME5CWEZfdzlhbFNUb19RX081M1pYQklUU05LbzBqRThPTXVRZmY5X24zeTJDZ21LbTdIcE5vdEhUNVYxempSZVpVIn0sICJub25jZSI6ICJPRGhqTW1NNE5EZ3RaV1F6TXkwMFlqbG1MV0V4TURZdE1EYzRaalExWlRSak9HVm0ifQ",
  "signature": "jbmYpvqER2HnUh8Bieob8eHJOuS3Pztypajb-YzDS74Wu3TFup8q8MVtvf1CjhxT527GTcBLXAv0RrcZWiOVXuMu9NtaGMbzVQQDzxsJ81-PEXv7_EtSgRMHjoa7iCJlgVAj-iudQ-aeBTNOpFms1T16V5jaJzLOj16mVYF-KbOeAzTfscVmMI3fTbmPXTL5t2TKochLs-gk0lBqJKoAwN02jWXHAYvllM8kHNuYqjd1GFv_qjwvT6rKqywDV_S2pKJTu74OpPdt-f6FNJEmpHiObkX-qV0o5leagPQDNqgacKyurKQTe-JOVOjnZGtXQE_1EXG7jESHf0KdAo8Th1VOBKRD5Fk961YpkQQa8zOIRSdxNTYM99VWQjva9D5FcP2PzVuufrjM0zdflpawsilZvfbLbO7IkoksFyJaMbaDis80s7pQKdYua3JktujD1C0Wm2FBGlV_QLwE0WV35PGM3NSv8K-8OqJQaYlSPg5GVVSDvSGOzaw8rBxtbWN9C7Knxrk-z4XcRT3AWXD1SolLL4oqDG2vjbkYag8ZbqyjeBQRnM1y16LQh5tspA1PsHdIfAOLxnGdJRZ-04t9IltcTA-hLTyJ-CAXyz6nY69gUvD9TkQMYbMtpNG-PCbDqJ0wf4YrdDZz5AwyOxN4M6d-4yOUTfteDO9ejKPLfTg"
}

The resulting answer:

{
  "code": 400,
  "detail": "INVALID_JSON_JWS",
  "details": "HTTP 400 Bad Request",
  "message": "MALFORMED_BAD_REQUEST",
  "type": "urn:ietf:params:acme:error:malformed"
}

Any idea what I'm doing wrong?

 

Thanks a lot and best regards,

Felix

2replies Oldest first
  • Oldest first
  • Newest first
  • Active threads
  • Popular
  • Hi Felix Fontein

     

    The JWS has duplicate keys alg and jwk in protected and unprotected headers.

    Therefore the jws was rejected by the server.

     

    Info from JWS spec:

    “ For a JWS, the members of the JSON object(s) representing the JOSE

       Header describe the digital signature or MAC applied to the JWS

       Protected Header and the JWS Payload and optionally additional

       properties of the JWS.  The Header Parameter names within the JOSE

       Header MUST be unique; JWS parsers MUST either reject JWSs with

       duplicate Header Parameter names or use a JSON parser that returns

       only the lexically last duplicate member name, as specified in

       Section 15.12 ("The JSON Object") of ECMAScript 5.1 [ECMAScript].”

     

    https://tools.ietf.org/html/rfc7515#section-4

     

    Regards,

    Andriy Mahats

    Reply Like
  • Hi Andriy Mahats

     

    Thanks a lot! That's indeed wrong; Let's Encrypt's ACME v1 endpoints never complained about it, I guess the parser they use returns only the lexically last duplicate member name. Anyway, with this (and a little other bugfixes I found along the way), I can now successfully issue certificates via Buypass - both staging and production (https://buypass.tlstest.fonga.ch/ 🎉)! I'm now preparing a PR (https://github.com/ansible/ansible/pull/61693) to fix this in acme_certificate.

     

    Thanks again and best regards,

    Felix

    Reply Like
Like Follow
  • 2 mths agoLast active
  • 2Replies
  • 27Views
  • 2 Following

Buypass Official Community

This is the official community of Buypass.  A Root CA located in Norway.