What does <Parse error reading JWS> exactly mean?

send req to
https://acme-staging-v02.api.letsencrypt.org/acme/new-acct

get response: Parse error reading JWS

Is it means that my request format is wrong ?
or
Signature is incorrect ?

1 Like

You'd need to share an example posted message but as far as I know when boulder deserializes your JWS it expects certain fields to be in a specific order or the values may have the wrong encoding

here is example:



import requests
import url64
import json
import base64
from jwcrypto import jwk, jws
from jwcrypto.common import json_encode
from pprint import pprint as pp

#
# HEAD newNonce
#
resp = requests.head('https://acme-staging-v02.api.letsencrypt.org/acme/new-nonce')
pp(resp.headers)
replay_nonce = resp.headers['Replay-Nonce']
print 'Nonce is:'
pp(replay_nonce)


session = requests.Session()
session.headers.update({'Content-Type': 'application/jose+json'})


protected_header = {
        "alg": "ES256",
        "nonce": url64.encode(replay_nonce),
        "url": "https://acme-staging-v02.api.letsencrypt.org/acme/new-acct",
}


payload = {
    "termsOfServiceAgreed": True,
    "contact": [
        "mailto:test_mail_new@sina.com"
    ]
}


req = {
    "protected": base64.urlsafe_b64encode(json.dumps(protected_header)),
    "payload": base64.urlsafe_b64encode(json.dumps(payload)),
}

print req


key = jwk.JWK.generate(kty='EC')


jwstoken = jws.JWS(json.dumps(payload))


jwk_param = key.export()


jwstoken.add_signature(
    key,
    'ES256',
    json.dumps(payload),
    # header=header,
    # json_encode({"kid": key.thumbprint()})
)
sig = jwstoken.serialize()


print sig


req.update({"signature": url64.encode(sig)})


print '=======req======='
pp(req)


resp = session.post(
    url='https://acme-staging-v02.api.letsencrypt.org/acme/new-acct',
    json=req,
)

print '========response========'
print resp.headers
print resp.json()

Why is your JWK not in your protected header?

You shouldn't need to urlencode the nonce.

You should be using the URL endpoints from the directory rather than hardcoding them.

this one is also get the same error response

What contains jwk_param exactly?

What is this mean?

In this example

I think URL endpoints is "https://acme-staging-v02.api.letsencrypt.org/acme/new-acct"

{"crv":"P-256","d":"sM-GxMaDA_J6mYkoH5M1wSDoLGoNw0oDeL4HlnINDBM","kty":"EC","x":"MBY9WUbM7yJ3HXEJgWNtFfPw-AGCTATgBJEyltYUmoM","y":"ycTOtaTzMP5w1v3b_KSsnxZF9OVMZ8y6WuldZwM0RXk"}

It is, but you shouldn't be hardcoding the URL into your code. It's OK for testing in the shortrun though.

Ok, I see.

This is testing code.

This looks fine.

Why are you reencoding the nonce though?

What is the value of url64.encode(replay_nonce)?

What is the value of replay_nonce?

Fixed this just then.

What's the code look like now?

import requests
import url64
import json
import base64
from jwcrypto import jwk, jws
from jwcrypto.common import json_encode
from pprint import pprint as pp

#
# HEAD newNonce
#
resp = requests.head('https://acme-staging-v02.api.letsencrypt.org/acme/new-nonce')
pp(resp.headers)
replay_nonce = resp.headers['Replay-Nonce']
print 'Nonce is:'
pp(replay_nonce)


session = requests.Session()
session.headers.update({'Content-Type': 'application/jose+json'})


key = jwk.JWK.generate(kty='EC')
jwk_param = key.export()




protected_header = {
        "alg": "ES256",
        "nonce": replay_nonce,
        "url": "https://acme-staging-v02.api.letsencrypt.org/acme/new-acct",
        "jwk": jwk_param
}


payload = {
    "termsOfServiceAgreed": True,
    "contact": [
        "mailto:test_mail_new@sina.com"
    ]
}


req = {
    "protected": base64.urlsafe_b64encode(json.dumps(protected_header)),
    "payload": base64.urlsafe_b64encode(json.dumps(payload)),
}

print req





jwstoken = jws.JWS(json.dumps(payload))





jwstoken.add_signature(
    key,
    'ES256',
    json.dumps(payload),
    # header=header,
    # json_encode({"kid": key.thumbprint()})
)
sig = jwstoken.serialize()


print sig


req.update({"signature": url64.encode(sig)})


print '=======req======='
pp(req)


resp = session.post(
    url='https://acme-staging-v02.api.letsencrypt.org/acme/new-acct',
    json=req,
)

print '========response========'
print resp.headers
print resp.json()

And with same error response.

I'm wondering if your True gets converted properly.

this one???

payload = {
"termsOfServiceAgreed": 'true',
"contact": [
"mailto:test_mail_new@sina.com"
]
}

that's a bug...

should be:
{"termsOfServiceAgreed":true}

in the output

This is Python.

bool value true is "True" , bool value false is "False".

not like javascript.

Right, but JSON is a Javascript format

My own client is in PHP.

When I json_encode this:
[
"termsOfServiceAgreed" => true
]

I get this:
{"termsOfServiceAgreed":true}

I'm not sure if it parses the same. I know booleans are a big source of headaches for JSON encoding.