Parse error reading JWS: Malformed, what am I doing wrong?

I am attempting to make a new account, I listed the directory and got a new nonce

Here is what i have made so far:

import * as jose from './jose/index.js';

export async function createAccount(nonce, newAccountUrl) {
    const { publicKey, privateKey } = await jose.generateKeyPair('ES256', { extractable: true });

    const jwk = await jose.exportJWK(publicKey);

    const payload = { termsOfServiceAgreed: true };
    const protectedHeader = {
        alg: "ES256",
        jwk,
        nonce: nonce,
        url: newAccountUrl,
    };

    const jws = new jose.FlattenedSign(new TextEncoder().encode(JSON.stringify(payload)));
    jws.setProtectedHeader(protectedHeader);
    const signed = await jws.sign(privateKey);

    const request = {
        method: 'POST',
        headers: {
            'Content-Type': 'application/jose+json'
        },
        body: JSON.stringify(signed) // accepted answer
    };

    const response = await fetch(newAccountUrl, request);
    if (!response.ok) {
        const errorData = await response.text();
        throw new Error(errorData || 'Unknown error');
    }

    return {
        answer: { account: await response.json(), location: response.headers.get('location') },
        nonce: response.headers.get('replay-nonce')
    };
}

JWT.io says that the signature is valid and no matter what I do I always get the same response.

request {
  method: 'POST',
  headers: { 'Content-Type': 'application/jose+json' },
  body: {
    signature: 'LuF2LdSkmGaX3YzxWnDZwqJJ9JguXFttwADcrilGmuTpBNPiVvRs7dg6ZugleF9PIcbAOU7UYD1Snf4o9FO4_w',
    payload: 'eyJ0ZXJtc09mU2VydmljZUFncmVlZCI6dHJ1ZX0',
    protected: 'eyJhbGciOiJFUzI1NiIsImp3ayI6eyJrdHkiOiJFQyIsIngiOiJVTHBzTm45azZsWDBlVTVjcnhuckR2YVhxYW5zVndtMnZ1TWpLUTRPancwIiwieSI6Ijk2Y1pqeFhvWUl6RnVqUG1mVVpYLVZFeURUd05FOS1JeDRQZXBEVk5XVFUiLCJjcnYiOiJQLTI1NiJ9LCJub25jZSI6IkZXOVN3TFNMRTRYZXFTNkwyRUliTGtlQl9kTnV4d3ZucWI5eUc1TExFY2FxSkRPczEzbyIsInVybCI6Imh0dHBzOi8vYWNtZS1zdGFnaW5nLXYwMi5hcGkubGV0c2VuY3J5cHQub3JnL2FjbWUvbmV3LWFjY3QifQ'
  }
}
Error: {
  "type": "urn:ietf:params:acme:error:malformed",
  "detail": "Parse error reading JWS",
  "status": 400
}

Edit:

If you are using Javascript and looking for help, You may find this useful: lets-encrypt.js

At the time of writing it only creates accounts

Is this the exact text you're POSTing? Because that's not JSON: your object keys need to be quoted strings as well, like:

{
    "signature": "LuF2LdSk...",
    "payload": "eyJ0ZXJt...",
    "protected": 'eyJhbGci..."
}

If not, can you provide the exact body of your message, rather than some in-memory representation of it?

6 Likes

Yeah that was it, can't believe I re-wrote this like 50 times and it was something so simple

I tried the built in crypto library, node-jose and jose and all along it was just that I didnt JSON.stringify the body but i swear i tried that at some point and got an error, but alas maybe something else was wrong at that exact moment. :rofl: :joy:

request {
  method: 'POST',
  headers: { 'Content-Type': 'application/jose+json' },
  statusText: 'Created',
  headers: Headers {
    server: 'nginx',
    date: 'Thu, 21 Nov 2024 23:20:37 GMT',
    'content-type': 'application/json',
    'content-length': '270',
    connection: 'keep-alive',
    'boulder-requester': '172648664',
    'cache-control': 'public, max-age=0, no-cache',
    link: '<https://acme-staging-v02.api.letsencrypt.org/directory>;rel="index", <https://letsencrypt.org/documents/LE-SA-v1.4-April-3-2024.pdf>;rel="terms-of-service"',
    location: 'https://acme-staging-v02.api.letsencrypt.org/acme/acct/172648664',
    'replay-nonce': 'FW9SwLSLTYDSfBGpmU8TkTLNI-HFtuO8xN9y84HZSdkYxk3ioX4',
    'x-frame-options': 'DENY',
    'strict-transport-security': 'max-age=604800'
  },
  body: ReadableStream { locked: false, state: 'readable', supportsBYOB: true },
  bodyUsed: false,
  ok: true,
  redirected: false,
  type: 'basic',
  url: 'https://acme-staging-v02.api.letsencrypt.org/acme/new-acct'
}

If you are using Javascript and looking for help, You may find this useful: lets-encrypt-http.js

At the time of writing it only creates accounts:

Account Created and Valid {
  account: {
    key: {
      kty: 'EC',
      crv: 'P-256',
      x: 'LzXKI--shZDknWDkrtJxfiyy-KOWaQFd7lNuSI2k8iQ',
      y: 'xMfF4ElwLDBojro9DOO8pMjCZ7ndZVzuowNsSAxh8Cs'
    },
    initialIp: '[removed personal information]',
    createdAt: '2024-11-22T01:48:21.807019552Z',
    status: 'valid'
  },
  location: 'https://acme-staging-v02.api.letsencrypt.org/acme/acct/172662314'
}
Next Nonce jDZhkUVk_t2phXMHKGG0ZnvjwP_GqXlrGbD72I_vvGacmEWq8FU
2 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.