Hi,
I’m developing an ACME client library.
When testing against the staging server, I get a lot of “malformed JWS verification error” replies.
Here are two examples of the same call briefly after each other (twice very soon after device boot), once with the infamous error, the other a valid call.
Am I overlooking something on my part, or is the staging server throwing a LOT of these ?
I (7786) Acme: QueryAcmeDirectory: ok
I (9476) Acme: RequestNewAccount(mailto:dannybackx@telenet.be) msg {
“termsOfServiceAgreed”: true,
“contact”: [
“mailto:dannybackx@telenet.be”
],
“onlyReturnExisting”: true
}
I (10586) Acme: RequestNewAccount : msg {
“protected”: “eyJ1cmwiOiAiaHR0cHM6Ly9hY21lLXN0YWdpbmctdjAyLmFwaS5sZXRzZW5jcnlwdC5vcmcvYWNtZS9uZXctYWNjdCIsICJqd2siOiB7Imt0eSI6ICJSU0EiLCAibiI6ICJ3ZUJFOUVZM21lRkdjbTYwTnpQdWhGSHVZemh6QnUxMXR6aUx0ZVlwVERxTGs2ZnF2ZTNjM3lJRDNwZXExXzJKV1psOGt5VVg3Y3NSVkNiWUFheHRsbDNnbGx5QnR4ekhjZlJrYl9iREdDT2J1cDFFS2ZpNDIwUnNiSHoxbEZmVEE3enA3XzMwQWhrOWNVd3F1MG1DdDlIeFVOQjFyNVJTSDRhZEptY0NrOE84dWZhUkZVdlRTVU5vcGlZRURqci0zM1BmS0hSX1dNdUZ1MGZvb21HamVHbGwyanVHR09iU1Vud29TRWxRcmZlLXRINXU5Q0ZiSmJHOFpfSGRrN3o1SG5XQ2lIZWtFTEVWcGU0Yk5fTXN4QS1RRF9Vb3NKVVI4T1M2eF81U1RiRzNaMEwtcmJ4X1pXanVuZFlQTmhRTnM5N2EzcDlMdFF3VzB3Z09jVU92ZnciLCAiZSI6ICJBUUFCIn0sICJhbGciOiAiUlMyNTYiLCAibm9uY2UiOiAiMDAwMWJDUDN2ekFjb3lmazg2RTEtODlaOERqX0RTdzRTTjZqRDhFd0pfZmVIZDAifQ”,
“payload”: “ewogICJ0ZXJtc09mU2VydmljZUFncmVlZCI6IHRydWUsCiAgImNvbnRhY3QiOiBbCiAgICAibWFpbHRvOmRhbm55YmFja3hAdGVsZW5ldC5iZSIKICBdLAogICJvbmx5UmV0dXJuRXhpc3RpbmciOiB0cnVlCn0”,
“signature”: “kDDJphCq0BpoDxAQdMMRBrNUwBbuldRAoLEU3Q7F1wQjciaSws4KmjBC9RQgKSH_IkC73yRvpOcZqBwjZOMNL6BycEaPmz6hhTm8akve2sDNyZB7ZjfmFkKpQBQmWnTFl7OIdRLKCfrIoNjpOAM4YawOuk_VxR24okhvA38GtflrI85b2eU”
}
I (12026) FTP Server: 28-12-2019 17:01:06 : 220 LightFTP server v2.0a ready
I (12546) Acme: HttpEvent: header Server value nginx
I (12546) Acme: HttpEvent: header Date value Sat, 28 Dec 2019 16:01:07 GMT
I (12546) Acme: HttpEvent: header Content-Type value application/problem+json
I (12556) Acme: HttpEvent: header Content-Length value 107
I (12566) Acme: HttpEvent: header Connection value keep-alive
I (12566) Acme: HttpEvent: header Cache-Control value public, max-age=0, no-cache
I (12576) Acme: HttpEvent: header Link value https://acme-staging-v02.api.letsencrypt.org/directory;rel=“index”
I (12586) Acme: HttpEvent: header Replay-Nonce value 0002emKJAuIhmoKQYqIAWzyFvTG81Yk261qpUOWxC-5R8Vg
I (12606) Acme: RequestNewAccount : JSON opened
E (12606) Acme: RequestNewAccount: failure 400 urn:ietf:params:acme:error:malformed JWS verification error
I (12626) Acme: ReadCertificate: we have a certificate in /spiffs/acme/certificate.pem
I (6226) Acme: QueryAcmeDirectory: ok
I (7916) Acme: RequestNewAccount(mailto:dannybackx@telenet.be) msg {
“termsOfServiceAgreed”: true,
“contact”: [
“mailto:dannybackx@telenet.be”
],
“onlyReturnExisting”: true
}
I (9026) Acme: RequestNewAccount : msg {
“protected”: “eyJ1cmwiOiAiaHR0cHM6Ly9hY21lLXN0YWdpbmctdjAyLmFwaS5sZXRzZW5jcnlwdC5vcmcvYWNtZS9uZXctYWNjdCIsICJqd2siOiB7Imt0eSI6ICJSU0EiLCAibiI6ICJ3ZUJFOUVZM21lRkdjbTYwTnpQdWhGSHVZemh6QnUxMXR6aUx0ZVlwVERxTGs2ZnF2ZTNjM3lJRDNwZXExXzJKV1psOGt5VVg3Y3NSVkNiWUFheHRsbDNnbGx5QnR4ekhjZlJrYl9iREdDT2J1cDFFS2ZpNDIwUnNiSHoxbEZmVEE3enA3XzMwQWhrOWNVd3F1MG1DdDlIeFVOQjFyNVJTSDRhZEptY0NrOE84dWZhUkZVdlRTVU5vcGlZRURqci0zM1BmS0hSX1dNdUZ1MGZvb21HamVHbGwyanVHR09iU1Vud29TRWxRcmZlLXRINXU5Q0ZiSmJHOFpfSGRrN3o1SG5XQ2lIZWtFTEVWcGU0Yk5fTXN4QS1RRF9Vb3NKVVI4T1M2eF81U1RiRzNaMEwtcmJ4X1pXanVuZFlQTmhRTnM5N2EzcDlMdFF3VzB3Z09jVU92ZnciLCAiZSI6ICJBUUFCIn0sICJhbGciOiAiUlMyNTYiLCAibm9uY2UiOiAiMDAwMWtpdkRBYW0wSDVpQldVVEhVR3JvcjlWa2g0b2FvQjZzYVhUSUlRUUVneHMifQ”,
“payload”: “ewogICJ0ZXJtc09mU2VydmljZUFncmVlZCI6IHRydWUsCiAgImNvbnRhY3QiOiBbCiAgICAibWFpbHRvOmRhbm55YmFja3hAdGVsZW5ldC5iZSIKICBdLAogICJvbmx5UmV0dXJuRXhpc3RpbmciOiB0cnVlCn0”,
“signature”: “SO-yJ4iee4lb5e1sJyuRVjBlLLwiKdq40kfJnPg9BSKP636wbnKWi7Mnz3y9zbJVilKqVoljos5jhImQFu04gRJKo2DCaOhzSm2jwp2Ntbscp3WtGg7YtyMk9a7Cy0c3z5EV3OmuXdB0bKPn3Ea0s9LlRXhRqyabc-8XbUwGR_H-Qmg1I7kTbwZb_QPc5YR-mw-FrTgdoOwmSE3nDc4CMEsv267nVS2J3bh5EzOSNpuQWeZwXvA5kdv9xr1SPjHKrcdHUAmHckcwAlTQr1vllwGtMmZXw_cu93BaISwunEnoZEBnUqIWjnc9HHlJ2u4E6OZpjsdI9OQFVrTlgc_lzA”
}
I (10526) FTP Server: 28-12-2019 17:04:10 : 220 LightFTP server v2.0a ready
I (10996) Acme: HttpEvent: header Server value nginx
I (10996) Acme: HttpEvent: header Date value Sat, 28 Dec 2019 16:04:11 GMT
I (10996) Acme: HttpEvent: header Content-Type value application/json
I (10996) Acme: HttpEvent: header Content-Length value 575
I (11006) Acme: HttpEvent: header Connection value keep-alive
I (11016) Acme: HttpEvent: header Cache-Control value public, max-age=0, no-cache
I (11026) Acme: HttpEvent: header Link value https://acme-staging-v02.api.letsencrypt.org/directory;rel=“index”
I (11036) Acme: HttpEvent: header Location value https://acme-staging-v02.api.letsencrypt.org/acme/acct/11649655
I (11046) Acme: HttpEvent: header Replay-Nonce value 0002StVNqIs-HRnTwNvCUjktajWyPP5akus9wjMPjGc_tYo
I (11056) Acme: HttpEvent: header X-Frame-Options value DENY
I (11056) Acme: HttpEvent: header Strict-Transport-Security value max-age=604800
I (11076) Acme: RequestNewAccount : JSON opened
E (11076) Acme: RequestNewAccount: reply_status ‘valid’
I (11086) Acme: ReadCertificate: we have a certificate in /spiffs/acme/certificate.pem
Here’s such an example. I’ve added code to write the nonce specified by the server, and obviously my code asks for a nonce after boot.
This time, there were two failures before a valid reply.
Danny
I (6496) Acme: QueryAcmeDirectory: ok
I (8186) Acme: setNonce(0001qdd3rfk_–4il5M1btz696-PR-1wVGPRH_7YZq7ErRY)
I (8196) Acme: RequestNewAccount(mailto:dannybackx@telenet.be) msg {
“termsOfServiceAgreed”: true,
“contact”: [
“mailto:dannybackx@telenet.be”
],
“onlyReturnExisting”: true
}
I (9296) Acme: RequestNewAccount : msg {
“protected”: “eyJ1cmwiOiAiaHR0cHM6Ly9hY21lLXN0YWdpbmctdjAyLmFwaS5sZXRzZW5jcnlwdC5vcmcvYWNtZS9uZXctYWNjdCIsICJqd2siOiB7Imt0eSI6ICJSU0EiLCAibiI6ICJ3ZUJFOUVZM21lRkdjbTYwTnpQdWhGSHVZemh6QnUxMXR6aUx0ZVlwVERxTGs2ZnF2ZTNjM3lJRDNwZXExXzJKV1psOGt5VVg3Y3NSVkNiWUFheHRsbDNnbGx5QnR4ekhjZlJrYl9iREdDT2J1cDFFS2ZpNDIwUnNiSHoxbEZmVEE3enA3XzMwQWhrOWNVd3F1MG1DdDlIeFVOQjFyNVJTSDRhZEptY0NrOE84dWZhUkZVdlRTVU5vcGlZRURqci0zM1BmS0hSX1dNdUZ1MGZvb21HamVHbGwyanVHR09iU1Vud29TRWxRcmZlLXRINXU5Q0ZiSmJHOFpfSGRrN3o1SG5XQ2lIZWtFTEVWcGU0Yk5fTXN4QS1RRF9Vb3NKVVI4T1M2eF81U1RiRzNaMEwtcmJ4X1pXanVuZFlQTmhRTnM5N2EzcDlMdFF3VzB3Z09jVU92ZnciLCAiZSI6ICJBUUFCIn0sICJhbGciOiAiUlMyNTYiLCAibm9uY2UiOiAiMDAwMXFkZDNyZmtfLS00aWw1TTFidHo2OTYtUFItMXdWR1BSSF83WVpxN0VyUlkifQ”,
“payload”: “ewogICJ0ZXJtc09mU2VydmljZUFncmVlZCI6IHRydWUsCiAgImNvbnRhY3QiOiBbCiAgICAibWFpbHRvOmRhbm55YmFja3hAdGVsZW5ldC5iZSIKICBdLAogICJvbmx5UmV0dXJuRXhpc3RpbmciOiB0cnVlCn0”,
“signature”: “RVDphECCYjxF69kwZMH1fxQwD6WN0ope_-GfU27auuzAuHpenYCM8xfwV0mzD60vNg”
}
I (10596) FTP Server: 28-12-2019 20:06:06 : 220 LightFTP server v2.0a ready
I (11466) Acme: HttpEvent: header Server value nginx
I (11466) Acme: HttpEvent: header Date value Sat, 28 Dec 2019 19:06:07 GMT
I (11466) Acme: HttpEvent: header Content-Type value application/problem+json
I (11476) Acme: HttpEvent: header Content-Length value 107
I (11486) Acme: HttpEvent: header Connection value keep-alive
I (11486) Acme: HttpEvent: header Cache-Control value public, max-age=0, no-cache
I (11496) Acme: HttpEvent: header Link value https://acme-staging-v02.api.letsencrypt.org/directory;rel=“index”
I (11506) Acme: HttpEvent: header Replay-Nonce value 0002wJd2M5gAVLxDxeqeLoIY6t3CkJBRxdT7xirtg4SCByM
I (11516) Acme: setNonce(0002wJd2M5gAVLxDxeqeLoIY6t3CkJBRxdT7xirtg4SCByM)
E (11526) Acme: RequestNewAccount: failure 400 urn:ietf:params:acme:error:malformed JWS verification error
I (11546) Acme: ReadCertificate: we have a certificate in /spiffs/acme/certificate.pem
I (7676) Acme: QueryAcmeDirectory: ok
I (9266) Acme: setNonce(0002j0ECrsFYbErEThQBxqd-RbtWDeR0yjH1GygkQnOr058)
I (9276) Acme: RequestNewAccount(mailto:dannybackx@telenet.be) msg {
“termsOfServiceAgreed”: true,
“contact”: [
“mailto:dannybackx@telenet.be”
],
“onlyReturnExisting”: true
}
I (10376) Acme: RequestNewAccount : msg {
“protected”: “eyJ1cmwiOiAiaHR0cHM6Ly9hY21lLXN0YWdpbmctdjAyLmFwaS5sZXRzZW5jcnlwdC5vcmcvYWNtZS9uZXctYWNjdCIsICJqd2siOiB7Imt0eSI6ICJSU0EiLCAibiI6ICJ3ZUJFOUVZM21lRkdjbTYwTnpQdWhGSHVZemh6QnUxMXR6aUx0ZVlwVERxTGs2ZnF2ZTNjM3lJRDNwZXExXzJKV1psOGt5VVg3Y3NSVkNiWUFheHRsbDNnbGx5QnR4ekhjZlJrYl9iREdDT2J1cDFFS2ZpNDIwUnNiSHoxbEZmVEE3enA3XzMwQWhrOWNVd3F1MG1DdDlIeFVOQjFyNVJTSDRhZEptY0NrOE84dWZhUkZVdlRTVU5vcGlZRURqci0zM1BmS0hSX1dNdUZ1MGZvb21HamVHbGwyanVHR09iU1Vud29TRWxRcmZlLXRINXU5Q0ZiSmJHOFpfSGRrN3o1SG5XQ2lIZWtFTEVWcGU0Yk5fTXN4QS1RRF9Vb3NKVVI4T1M2eF81U1RiRzNaMEwtcmJ4X1pXanVuZFlQTmhRTnM5N2EzcDlMdFF3VzB3Z09jVU92ZnciLCAiZSI6ICJBUUFCIn0sICJhbGciOiAiUlMyNTYiLCAibm9uY2UiOiAiMDAwMmowRUNyc0ZZYkVyRVRoUUJ4cWQtUmJ0V0RlUjB5akgxR3lna1FuT3IwNTgifQ”,
“payload”: “ewogICJ0ZXJtc09mU2VydmljZUFncmVlZCI6IHRydWUsCiAgImNvbnRhY3QiOiBbCiAgICAibWFpbHRvOmRhbm55YmFja3hAdGVsZW5ldC5iZSIKICBdLAogICJvbmx5UmV0dXJuRXhpc3RpbmciOiB0cnVlCn0”,
“signature”: “evpg40zK-CtebTThlmNeVe_L8H42a-10ovtaEw”
}
I (12026) FTP Server: 28-12-2019 20:09:17 : 220 LightFTP server v2.0a ready
I (12136) Acme: HttpEvent: header Server value nginx
I (12136) Acme: HttpEvent: header Date value Sat, 28 Dec 2019 19:09:17 GMT
I (12136) Acme: HttpEvent: header Content-Type value application/problem+json
I (12146) Acme: HttpEvent: header Content-Length value 107
I (12156) Acme: HttpEvent: header Connection value keep-alive
I (12156) Acme: HttpEvent: header Cache-Control value public, max-age=0, no-cache
I (12166) Acme: HttpEvent: header Link value https://acme-staging-v02.api.letsencrypt.org/directory;rel=“index”
I (12176) Acme: HttpEvent: header Replay-Nonce value 0001O3Ei8eqN-KTKD6YsQMhzYB41YDNvnV8Viy8DjPbNelg
I (12186) Acme: setNonce(0001O3Ei8eqN-KTKD6YsQMhzYB41YDNvnV8Viy8DjPbNelg)
E (12196) Acme: RequestNewAccount: failure 400 urn:ietf:params:acme:error:malformed JWS verification error
I (12216) Acme: ReadCertificate: we have a certificate in /spiffs/acme/certificate.pem
I (7806) Acme: QueryAcmeDirectory: ok
I (9496) Acme: setNonce(00024IfB5HG9dcipE8IiUOSCEvPnBdLhtRRJW3RHgPhvrGM)
I (9506) Acme: RequestNewAccount(mailto:dannybackx@telenet.be) msg {
“termsOfServiceAgreed”: true,
“contact”: [
“mailto:dannybackx@telenet.be”
],
“onlyReturnExisting”: true
}
I (10606) Acme: RequestNewAccount : msg {
“protected”: “eyJ1cmwiOiAiaHR0cHM6Ly9hY21lLXN0YWdpbmctdjAyLmFwaS5sZXRzZW5jcnlwdC5vcmcvYWNtZS9uZXctYWNjdCIsICJqd2siOiB7Imt0eSI6ICJSU0EiLCAibiI6ICJ3ZUJFOUVZM21lRkdjbTYwTnpQdWhGSHVZemh6QnUxMXR6aUx0ZVlwVERxTGs2ZnF2ZTNjM3lJRDNwZXExXzJKV1psOGt5VVg3Y3NSVkNiWUFheHRsbDNnbGx5QnR4ekhjZlJrYl9iREdDT2J1cDFFS2ZpNDIwUnNiSHoxbEZmVEE3enA3XzMwQWhrOWNVd3F1MG1DdDlIeFVOQjFyNVJTSDRhZEptY0NrOE84dWZhUkZVdlRTVU5vcGlZRURqci0zM1BmS0hSX1dNdUZ1MGZvb21HamVHbGwyanVHR09iU1Vud29TRWxRcmZlLXRINXU5Q0ZiSmJHOFpfSGRrN3o1SG5XQ2lIZWtFTEVWcGU0Yk5fTXN4QS1RRF9Vb3NKVVI4T1M2eF81U1RiRzNaMEwtcmJ4X1pXanVuZFlQTmhRTnM5N2EzcDlMdFF3VzB3Z09jVU92ZnciLCAiZSI6ICJBUUFCIn0sICJhbGciOiAiUlMyNTYiLCAibm9uY2UiOiAiMDAwMjRJZkI1SEc5ZGNpcEU4SWlVT1NDRXZQbkJkTGh0UlJKVzNSSGdQaHZyR00ifQ”,
“payload”: “ewogICJ0ZXJtc09mU2VydmljZUFncmVlZCI6IHRydWUsCiAgImNvbnRhY3QiOiBbCiAgICAibWFpbHRvOmRhbm55YmFja3hAdGVsZW5ldC5iZSIKICBdLAogICJvbmx5UmV0dXJuRXhpc3RpbmciOiB0cnVlCn0”,
“signature”: “c1lSh9q2YvJAG9KW_80JDE_Y9GWCFaqd1dVIhAItKZ7evq-0h88SJJOlhSxnjePXQJ2ND1HENti48jJ4OSuStm2ufKY_Lfvyrzfw7GcSheokvzV2paUM_D9ZeSY6P91mOPIVawJuLTzEL0zlD_BqId0K7e-CQMQliUK8Gg4sf1aA9_gvBYVwR_lsXS80DFTIm8q2Zq00zjkT5FPrOJw5BD-kJxqnrQv0nlroi3aAanKmMK76pVXTWeeYGFDztY-9wGdW_PZbt5SZEws-L6Yv3rgRXF3pKH4nRzeXeYtaAVXdY2W0eFXIL3-eLoFFuV3V8MHjNZ5TbMm-yxSlec3x9A”
}
I (12026) FTP Server: 28-12-2019 20:09:45 : 220 LightFTP server v2.0a ready
I (12576) Acme: HttpEvent: header Server value nginx
I (12576) Acme: HttpEvent: header Date value Sat, 28 Dec 2019 19:09:46 GMT
I (12576) Acme: HttpEvent: header Content-Type value application/json
I (12586) Acme: HttpEvent: header Content-Length value 575
I (12586) Acme: HttpEvent: header Connection value keep-alive
I (12596) Acme: HttpEvent: header Cache-Control value public, max-age=0, no-cache
I (12606) Acme: HttpEvent: header Link value https://acme-staging-v02.api.letsencrypt.org/directory;rel=“index”
I (12616) Acme: HttpEvent: header Location value https://acme-staging-v02.api.letsencrypt.org/acme/acct/11649655
I (12626) Acme: HttpEvent: header Replay-Nonce value 000187DMDD_zxlrKUGXEFbSxAcr5Dnns-MaSiNSRu_IhPM8
I (12636) Acme: setNonce(000187DMDD_zxlrKUGXEFbSxAcr5Dnns-MaSiNSRu_IhPM8)
I (12646) Acme: HttpEvent: header X-Frame-Options value DENY
I (12646) Acme: HttpEvent: header Strict-Transport-Security value max-age=604800
E (12666) Acme: RequestNewAccount: reply_status ‘valid’
I (12676) Acme: ReadCertificate: we have a certificate in /spiffs/acme/certificate.pem
It is hard to diagnose only knowing {N,E} and the signature. If you can produce a similar log file with the full private key, that would probably be enough to figure out what’s going wrong.
I noticed that in both cases, the truncation is happening on a NUL byte. So the problem is likely related to one of the uses of strlen, or the construction of String without specifying length.
I’m sure there have been versions of this bug in thousands of pieces of software, because programmers are so used to dealing with null-terminated strings, especially in assembly and in languages derived from C. Cryptography is tricky here because you sometimes have (1) potentially variable-length objects that (2) need to be serialized and shown to users and/or included inside network protocols, but (3) are pseudorandom data that includes null bytes all over the place. If you get tempted to use a string anywhere instead of a fixed-size structure because of (1), or get tempted to use a string instead of a byte array or byte buffer because of (2), it’s easy to get tripped up when the string-manipulating functions don’t do what you expected with the object.
Some languages make it a lot easier to make this mistake than others, but it’s a good thing to watch out for!