Yet another "Parsing error reading JWS" creating account

Hello Community,

at the Moment I am writing a new acme client in ABAP.
I'm using it against pebble in my personal testing network.
My Pebble CA runs at 192.168.2.210.

what i did so far:

  • get the directories
  • get the nounce
  • create an account

At the moment I am between creating an account and submitting orders I think.

My account creation post looks like:

{
 "alg":"RS256",
 "nonce":"S8XEix1_iKeW6nWrNzy9Rg",
 "jwk":{
		 "kty":"RSA",
		 "n":"mm90XmCUI89DpyEVgkFiIZZywo16JTbAHY2O279Zi1p12JF13EugKkAtl8sUp4NAaP4u6AD1TsHz6QIym26iGr0KZKZMxT08x44gSy8fsNgMAsI1VnO9b75wxoPXCAYbemZ8rySFHptazDh3OSXstHTZ5fRhvO2eiOXIcTl_0oMRjQgDSnvg5kBlGfnmdP90xXiaxPSnp8DMQ-N3bHaKF95UXozk42h5HnGGm5bJb1Oh2PVavvY3P72uj3EEb70J9bQgOREOht8ApYpdHl-LRpn35RSTsXfciimC0BIbG5POfSeJ4LEub3ouAOlnvGgz58qiUZiUeFVuPM_zMA558w",
		 "e":"AQAB",
		 "use":"sig"
		 },
 "url":"https://192.168.2.210:14000/https://192.168.2.210:14000/sign-me-up"
}
{
 "contact":["mailto:mymail@email.org"],
 "termsOfServiceAgreed": true
}

The "url" looks strange to me but pebble seem to want it like that.
Btw, I think at the moment Pebble is not allowed to send emails. Is this important for creating an account or anything like that?

The Response from Pebble is:

{
 "status":"valid",
 "contact":[
            "mailto:mymail@email.org" 
           ],
 "orders":"https://192.168.2.210:14000/list-orderz/1",
 "key": {
         "use":"sig",
         "kty":"RSA",
         "n":"mm90XmCUI89DpyEVgkFiIZZywo16JTbAHY2O279Zi1p12JF13EugKkAtl8sUp4NAaP4u6AD1TsHz6QIym26iGr0KZKZMxT08x44gSy8fsNgMAsI1VnO9b75wxoPXCAYbemZ8rySFHptazDh3OSXstHTZ5fRhvO2eiOXIcTl_0oMRjQgDSnvg5kBlGfnmdP90xXiaxPSnp8DMQ-N3bHaKF95UXozk42h5HnGGm5bJb1Oh2PVavvY3P72uj3EEb70J9bQgOREOht8ApYpdHl-LRpn35RSTsXfciimC0BIbG5POfSeJ4LEub3ouAOlnvGgz58qiUZiUeFVuPM_zMA558w",
         "e":"AQAB"
        }
}

Is this "n" now my new account key?

From there I am not really sure what to send.
I tried this:

{
  "alg": "RS256",
  "nonce": "bKJd9KN90QdYXUbuwjTvOw",
  "kid": "https://192.168.2.210:14000/list-orderz/1",
  "url": "https://192.168.2.210:14000/https://192.168.2.210:14000/order-plz"
}
{
  "contact": [
    "mailto:mymail@email.org"
  ],
  "termsOfServiceAgreed": true
}

but I always get:

{
 "type":"urn:ietf:params:acme:error:malformed",
 "detail":"Key ID (kid) in JWS header missing expected URL prefix",
 "status": 400
}

Is there a way to get more specific detail on what exactly the CA wants to get in what field at what time?
As i understood, the ACME documentation is not that specific most of the time.

Best regards,

Robin

Hi @RobinK

I don't use Pebble, but that url is wrong.

Please compare it with the informations you have sent. It's exact the same content.

An ACME server doesn't create your public key. So you have to create a key pair and use it.

Your url is wrong, that's all. May be you have to configure Pebble to declare allowed kid values.

Hi @JuergenAuer

When I try to set the "url" to another value it always says:

JWS header parameter 'url' incorrect.
Expected "https://192.168.2.210:14000/https://192.168.2.210:14000/sign-me-up",
got "https://192.168.2.210:14000/sign-me-up"

I already recognized that. My question meant: Is that public key I personally created now the key of the new account.

Uhh, that does not look right at all.

What are you putting into the Host header and into the Request Path in your HTTP client?

I filed JWS url calculation can't handle absoluteURI form Request-URIs · Issue #341 · letsencrypt/pebble · GitHub with what I think might be the cause, but if you can use non-absolute URIs, that might help avoid the issue.

2 Likes

That looks wrong to me too. Can you post your pebble-config.json and/or command line arguments used to invoke pebble? (I think they can override the config file)

2 Likes

Thank you for your replies.

At first: I repaired a bug in my client. Now i get another error. (later more)

What might be be an important Information is that:
The HOST with Pebble CA is not my local machine and the client runs on another machine.

I changed that 192.168.2.210 to myhost.speedport.ip
My Host Header is now
myhost.speedport.ip:14000
Pebble still wants that strange
https://myhost.speedport.ip:14000/https://myhost.speedport.ip:14000/sign-me-up

The Request path in my http client is what i get from pebble for account creation:
https://myhost.speedport.ip:14000/sign-me-up

When I use this strange doubled data in "url" it seems to be ok for pebble.
The Response is:

{
 "status":"valid",
 "contact": [
    "mailto:mymail@email.org"
 ],
 "orders": "https://myhost.speedport.ip:14000/list-orderz/1",
 "key": {
    "use": "sig",
    "kty": "RSA",

 "n": "mm90XmCUI89DpyEVgkFiIZZywo16JTbAHY2O279Zi1p12JF13EugKkAtl8sUp4NAaP4u6AD1TsHz6QIym26iGr0KZKZMxT08x44gSy8fsNgMAsI1VnO9b75wxoPXCAYbemZ8rySFHptazDh3OSXstHTZ5fRhvO2eiOXIcTl_0oMRjQgDSnvg5kBlGfnmdP90xXiaxPSnp8DMQ-N3bHaKF95UXozk42h5HnGGm5bJb1Oh2PVavvY3P72uj3EEb70J9bQgOREOht8ApYpdHl-LRpn35RSTsXfciimC0BIbG5POfSeJ4LEub3ouAOlnvGgz58qiUZiUeFVuPM_zMA558w",
    "e": "AQAB"
 }
}

When I afterwards try to send a post request either to
https://myhost.speedport.ip:14000/list-orderz/1
or
https://myhost.speedport.ip:14000/order-plz/
I get 500 Internal server error because I get no response within 60 seconds.

An example of what I tried to send is:

{
  "alg": "RS256",
  "nonce": "ZDX0LGMk8wy65tpPnKpPNw",
  "kid": "test",
  "url": "https://myhost.speedport.ip:14000/https://myhost.speedport.ip:14000/sign-me-up"
}
{
  "contact": [
    "mailto:mymail@email.org"
  ],
  "termsOfServiceAgreed": true
}

Maybe I don't get how it should be used.

My pebble config is:

{                                                                                                                                                                                                           
  "pebble": {                                                                                                                                                                                               
    "listenAddress": "0.0.0.0:14000",                                                                                                                                                                       
    "managementListenAddress": "0.0.0.0:15000",                                                                                                                                                             
    "certificate": "/root/src/github.com/letsencrypt/pebble/test/certs/selfmade3/cert.pem",                                                                                                                 
    "privateKey": "/root/src/github.com/letsencrypt/pebble/test/certs/selfmade3/key.pem",                                                                                                                   
    "httpPort": 5002,                                                                                                                                                                                       
    "tlsPort": 5001,                                                                                                                                                                                        
    "ocspResponderURL": "",                                                                                                                                                                                 
    "externalAccountBindingRequired": false                                                                                                                                                                 
  }                                                                                                                                                                                                         
}

I start it with:

/root/bin/pebble -config /root/src/github.com/letsencrypt/pebble/test/config/pebble-config-myhost.json

If you're using CL_HTTP_CLIENT=>CREATE, can you try using CL_HTTP_CLIENT=>CREATE_BY_URL?

I am hoping that the latter will give a relative path, like Pebble's JWS code is expecting. (I think Pebble is technically in the wrong here).

I tried it but still have the same issue with the "url" (and the http 500).

:frowning: . Wish I could help more, but it doesn't look like it's possible to get a local ABAP server to try for myself.

I suspect the HTTP request line generated by the ABAP HTTP client is the problem but it's hard to say conclusively.

Wenn I run the request against an external request catcher site I cannot see anything suspicious.
( Exept the fact that it always sends the
Content-Type header as application/jose+json; charset=utf-8.
This is the reason I am using pebble.
We changed the constant which checks for
application/jose+json
to
application/jose+json; charset=utf-8
I already created an incident at SAP for this issue. )

When I convert the flattened json to compact serialization and parse it at jwt.io the protected header and the payload looks as mentioned obove.

Do you think the HTTP code 500 is a result of the url issue?

I recognized that i get the http 500 because the connection seems to get closed.
Not sure why but if i open it again for the orders request I am back at:

I'm out of ideas. The config and invocation look good to me. :frowning:

Found out that Pebble is not wrong at this point.
An added check would be nice but it is not neccecarily a failure.

Searched trough pebbles code and found out that pebble wants a "url" value of HOST + URI which should be for example:
https://myhost.speedport.ip:14000 + /sign-me-up

In ABAP it seems to be ok to set the uri to
https://myhost.speedport.ip:14000/sign-me-up
This causes pebble to want the given uri and hostname to be:
https://myhost.speedport.ip:14000/https://myhost.speedport.ip:14000/sign-me-up

I now set the uri to /sign-me-up and it works as expected.

Obviously I couldn't check this againt a request catcher site.

now again it sais:

{
"type":"urn:ietf:params:acme:error:malformed",
"detail":"Key ID (kid) in JWS header missing expected URL prefix",
"status": 400
}

Even though I am no golang native speaker I've looked a bit deeper into pebbles code.

In file wfe.go (github link) I found the function causing "Key ID (kid) in JWS header missing expected URL prefix".

In line 733 it is checking if the kid (here accountURL) has the desired "prefix" which is set in line 744

	prefix := wfe.relativeEndpoint(request, acctPath)
	if !strings.HasPrefix(accountURL, prefix) {
		return nil, acme.MalformedProblem("Key ID (kid) in JWS header missing expected URL prefix")

The constant acctPath is set to "/my-account/" (in line 45)

The problem is:
When I create an account under "/sign-me-up"
I get the "order" object
https://myhost.speedport.ip:14000/list-orderz/1
but Pebble wants me to send a kid which is:
https://myhost.speedport.ip:14000/my-account/1

So when I hardcode this into my request the issue does not occur again.
This is no option for prod environments of course.
I don't even get this path from the directory request in the beginning.

Maybe I am doing the wrong reqests:

  • get directory names /dir
  • get nonce /nonce-plz
  • create account /sign-me-up
    here i get: https://myhost.speedport.ip:14000/list-orderz/1
  • get orders /order-plz - where i get the problems with wrom path "prefix"

The only other path options is have are /revoke-cert and /rollover-account-key

Is this a pepple issue or am I using it wrong?