Hi,
I read through a lot of posts on similar errors but can't get to get it to work completely.
Developing a custom client and trying to create a new account, using Pebble hosted locally as ACME server.
I tried different formats for the request to be send to pebble which result in different error messages.
Using Python as programming language;
My JWT is valid: jwt.io
Error message 1 that I get:
{'type': 'urn:ietf:params:acme:error:malformed', 'detail': "Parse error reading JWS: invalid character 'e' looking for beginning of value", 'status': 400}
with payload created as follows:
public_key = self.signature_acme.get_public_key_json()
protected = {
"alg": "RS256",
"jwk": public_key,
"nonce": self.nonce,
"url": self.endpoints["newAccount"]
}
payload = {
"termsOfServiceAgreed": "true",
"contact": [
"mailto:test@gmail.com"
]
}
encoded_protected = self.signature_acme.base64url_encode(protected)
encoded_payload = self.signature_acme.base64url_encode(payload)
msg = f"{encoded_protected}.{encoded_payload}"
signature = self.signature_acme.sign_string(msg)
final_payload_data_1 = f"{msg}.{signature}"
# is_valid = self.signature_acme.verify_signature(message, signature, public_key)
print(f"Sending message to ACME Server to create new Account: {final_payload_data_1}")
headers = {"content-type": "application/jose+json"}
try:
response = requests.post(url=self.endpoints["newAccount"], verify=self.server_cert_location,
data=final_payload_data_1,
headers=headers)
response_body = json.loads(response.content)
return response_body
except requests.exceptions.RequestException as e:
print(e)
encode:
def base64url_encode(self, obj_to_encode):
json_str = json.dumps(obj_to_encode)
json_bytes = json_str.encode('utf-8')
base64_bytes = base64.urlsafe_b64encode(json_bytes)
return base64_bytes.decode('utf-8').rstrip('=')
sign:
def sign_string(self, message):
print("Sign message")
# Convert string to bytes
private_key = self.jwk_to_private_key()
message_bytes = message.encode('utf-8')
signature = private_key.sign(
message_bytes,
padding.PKCS1v15(),
hashes.SHA256()
)
return base64.urlsafe_b64encode(signature).decode('utf-8').rstrip('=')
As the JWT is correct and the signature verification works (jwt.io) I tried several different ways to send the message resulting in different errors.
Payload as json:
final_payload_2 = {
"protected": encoded_protected,
"payload": encoded_payload,
"signature": signature
}
# is_valid = self.signature_acme.verify_signature(message, signature, public_key)
headers = {"content-type": "application/jose+json"}
try:
response = requests.post(url=self.endpoints["newAccount"], verify=self.server_cert_location,
data=final_payload_2,
headers=headers)
response_body = json.loads(response.content)
return response_body
except requests.exceptions.RequestException as e:
print(e)
results in:
{'type': 'urn:ietf:params:acme:error:malformed', 'detail': "Parse error reading JWS: invalid character 'p' looking for beginning of value", 'status': 400}
trying to specify the input as json in the post with:
try:
response = requests.post(url=self.endpoints["newAccount"], verify=self.server_cert_location,
json=final_payload_2,
headers=headers)
results in this error:
{'type': 'urn:ietf:params:acme:error:malformed', 'detail': 'Error unmarshaling body JSON', 'status': 400}
Trying to dump the json with json.dumps as follows results in yet another error:
response = requests.post(url=self.endpoints["newAccount"], verify=self.server_cert_location,
json=json.dumps(final_payload_2),
headers=headers)
results in error:
{'type': 'urn:ietf:params:acme:error:malformed', 'detail': 'Parse error reading JWS: json: cannot unmarshal string into Go value of type struct { Header map[string]string; Signatures []interface {} }', 'status': 400}
At this point I'm just blindly trying things out and don't know anymore what can be wrong, especially as the signature is valid ... . My guess is that I'm somehow sending it in the wrong way / format to pebble and that's why it can't be processed properly.
Any help or pointers are very appreciated