{Urn ietf:params:acme error malformed Parse error reading JWS status 400}

Need Hep With

{
"type": "urn:ietf:params:acme:error:malformed",
"detail": "Parse error reading JWS",
"status": 400
}

Request

{
"header": {
"alg": "RS256",
"jwk": {
"e": "AQAB",
"kty": "RSA",
"n": "pSb37Nx2sCZFbC0uIsNn7USlYi0mhXuiDOUmv7CqhgdvBFiLG3aupF1BRD1y5J97Qw_dyFBOprFqoaYw7MIbxQbjTkCttZWiVdyzwj4A1DGydBI9vES7FabjjWjn4lkJhrxglemaq-6WTh6K5_WD4SF5_LcYBNqZwnrGGo1q_rhrREyhu9Q0agSXkVmO44Gu1UzahV0FtCc6pCY8zhM1MChRWzOrCRW25RxoxZWy9jfS1frUMbhRfGq8XbHE3e5Z8K5-h2aRg5HmRJWOsHffYmXunziO4lis5LvSyn7F10hlF149IZ6hVjP7JaincXf1GPrRptpVtm4O5KKWYQeZKw"
}
},
"protected": "ewogImFsZyI6ICJSUzI1NiIsCiAiandrIjogewogICJlIjogIkFRQUIiLAogICJrdHkiOiAiUlNBIiwKICAibiI6ICJwU2IzN054MnNDWkZiQzB1SXNObjdVU2xZaTBtaFh1aURPVW12N0NxaGdkdkJGaUxHM2F1cEYxQlJEMXk1Sjk3UXdfZHlGQk9wckZxb2FZdzdNSWJ4UWJqVGtDdHRaV2lWZHl6d2o0QTFER3lkQkk5dkVTN0ZhYmpqV2puNGxrSmhyeGdsZW1hcS02V1RoNks1X1dENFNGNV9MY1lCTnFad25yR0dvMXFfcmhyUkV5aHU5UTBhZ1NYa1ZtTzQ0R3UxVXphaFYwRnRDYzZwQ1k4emhNMU1DaFJXek9yQ1JXMjVSeG94Wld5OWpmUzFmclVNYmhSZkdxOFhiSEUzZTVaOEs1LWgyYVJnNUhtUkpXT3NIZmZZbVh1bnppTzRsaXM1THZTeW43RjEwaGxGMTQ5SVo2aFZqUDdKYWluY1hmMUdQclJwdHBWdG00TzVLS1dZUWVaS3ciCiB9LAogImtpZCI6ICIiLAogIm5vbmNlIjogIkcwN0pYS190NWI3amhWenNtS3ZaaGFZcDdqSzg1NzFZSUZzU2RFdkdndk0iLAogInVybCI6ICJodHRwczovL2FjbWUtdjAyLmFwaS5sZXRzZW5jcnlwdC5vcmcvYWNtZS9uZXctYWNjdCIKfQ",
"payload": "ewogInRlcm1zT2ZTZXJ2aWNlQWdyZWVkIjogdHJ1ZSwKICJjb250YWN0IjogWwogICJtYWlsdG86c2V0ZGNAZ21haWwuY29tIiwKICAibWFpbHRvOnNldGRjMUBnbWFpbC5jb20iCiBdCn0",
"signature": "X2eGFaT6pj4ENsmjbCqIaQJKF9KD9Kyu7SJz2ixFy6SJLLGab7uNanZtUUciw0jKtWKyn-Eul59mPNlwnWhWuO6d3AJJ_wAyO2YbdwJPJT0Gm5R2Ikvbr99kzc_zqNUp135AOY4TqNa56n01_y2r75cqWTNVSR6drvS0SAdphHjR2tgisX4fBuRLpViDVMowxSVSnIYDbOt7KUGwWg0RAjcrA_IDZftAVv66QdUxdz-KGIyCqmx1OBJxO9vZrNVv1rs4JCD4v0Gh-yYz1_eVIi5nmhziAsKAhEk1WAeNC5u1zjqXNcuTtOo1C_JmSc0UkIoi3FKxg1kqlyW9UgaiuA"
}

Response

{
"type": "urn:ietf:params:acme:error:malformed",
"detail": "Parse error reading JWS",
"status": 400
}

Code

package main

import (
"net/http"
"bytes"
"encoding/base64"
"crypto/rsa"
"log"
"crypto/rand"
"math/big"
"fmt"
"encoding/json"

"io/ioutil"
"crypto/sha256"
"crypto"
)

type Jwk struct {
E string json:"e"
Kty string json:"kty"
N string json:"n"
}

type Header struct {
Alg string json:"alg"
Jwk Jwk json:"jwk"
}

type Protected struct {
Alg string json:"alg"
Jwk Jwk json:"jwk, omitempty"
Kid string json:"kid, omitempty"
Nonce string json:"nonce"
URL string json:"url"
}

type Payload struct {
TermsOfServiceAgreed bool json:"termsOfServiceAgreed"
Contact string json:"contact"
}

type AcmeRequest struct {
Header Header json:"header"
Protected Protected json:"protected"
Payload Payload json:"payload"
Signature string json:"signature"
}

type Signature struct {
Protected string
Payload string
}

func (signature Signature) join() string {

return fmt.Sprintf("%s.%s", signature.Protected, signature.Payload)
}

type Account struct {
Status string json:"status"
Contact string json:"contact"
TermsOfServiceAgreed bool json:"termsOfServiceAgreed"
Orders string json:"orders"
}

func Send(b byte) {
request, _ := http.NewRequest("POST", "https://acme-staging-v02.api.letsencrypt.org/acme/new-acct", bytes.NewBuffer(b))
request.Header.Set("Content-Type", "application/jose+json")
request.Header.Set("User-Agent", "Vighnesh-Go v2.0")
request.Header.Set("Accept-Language", "en")
request.Header.Set("Access-Control-Allow-Origin", "*")

client := &http.Client{}
resp, err := client.Do(request)
if err != nil {
panic(err)
}
defer resp.Body.Close()

body, _ := ioutil.ReadAll(resp.Body)
fmt.Println("response Body:", string(body))
}

func GetNonce() (string, error) {
response, err := http.Get("https://acme-staging-v02.api.letsencrypt.org/acme/new-nonce")
return response.Header["Replay-Nonce"][0], err
}

func main() {

nonce, _ := GetNonce()
fmt.Println(nonce)
acmeRequest := AcmeRequest{}

privkey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
log.Printf("failed to generate private key: %s", err)
return
}

pubKey := &privkey.PublicKey
e := base64URLEncode(big.NewInt(int64(pubKey.E)).Bytes())
n := base64URLEncode(pubKey.N.Bytes())
kty := "RSA"

acmeRequest.Header.Alg = "RS256"
acmeRequest.Header.Jwk.E = e
acmeRequest.Header.Jwk.Kty = kty
acmeRequest.Header.Jwk.N = n

acmeRequest.Protected.Alg = "RS256"
acmeRequest.Protected.URL = "https://acme-v02.api.letsencrypt.org/acme/new-acct"

acmeRequest.Protected.Jwk.E = e
acmeRequest.Protected.Jwk.Kty = kty
acmeRequest.Protected.Jwk.N = n

acmeRequest.Protected.Nonce = nonce

contact := string{"mailto:setdc@gmail.com", "mailto:setdc1@gmail.com"}
acmeRequest.Payload.Contact = contact
acmeRequest.Payload.TermsOfServiceAgreed = true

protectedJson, _ := json.MarshalIndent(acmeRequest.Protected, "", " ")
//fmt.Println("protected:", string(protectedJson))

payloadJson, _ := json.MarshalIndent(acmeRequest.Payload, "", " ")
//fmt.Println("payload:", string(payloadJson))

urlEncodedProtected := base64URLEncode(protectedJson)
urlEncodedPayload := base64URLEncode(payloadJson)

acmeRequest.Signature = Signature{urlEncodedProtected, urlEncodedPayload}.join()

type EncodedAcmeRequest struct {
Header Header json:"header"
Protected string json:"protected"
Payload string json:"payload"
Signature string json:"signature"
}

encodedACMERequest := EncodedAcmeRequest{}

signed, signError := Sign(privkey, byte(acmeRequest.Signature))
if signError != nil {
fmt.Println("Could not sign", signError)
}
//fmt.Println("signed", string(signed))
signature := base64URLEncode(signed)
fmt.Println(signature)

encodedACMERequest.Protected = urlEncodedProtected
encodedACMERequest.Header = acmeRequest.Header
encodedACMERequest.Payload = urlEncodedPayload
encodedACMERequest.Signature = signature

b, err := json.MarshalIndent(encodedACMERequest, "", " ")
unsigned := Unsign(pubKey, byte(acmeRequest.Signature), signed)
fmt.Println("unsigned", unsigned)
fmt.Println(string(b))
Send(signed)

}

func Sign(privateKey *rsa.PrivateKey, data byte) (byte, error) {
sha := sha256.New()
sha.Write(data)
sha256Hash := sha.Sum(nil)
return rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, sha256Hash)
}

// Unsign verifies the message using a rsa-sha256 signature
func Unsign(publicKey *rsa.PublicKey, message byte, signed byte) error {
sha := sha256.New()
sha.Write(message)
sha256Hash := sha.Sum(nil)
return rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, sha256Hash, signed)
}

func base64URLEncode(data byte) string {
return base64.RawURLEncoding.EncodeToString(data)
}

func base64URLDecode(data string) (byte, error) {
return base64.RawURLEncoding.DecodeString(data)
}

@jsha

Can you take a look at this…

(I might having the same issue when i’m getting certs from zerossl and sslforfree.com)

Thank you

This error means that the JSON you sent was malformed, or that jose.ParseSigned considers it malformed. I’d recommend running your generated JSON through a JSON decoder (e.g. python -mjson.tool) and correcting errors until it parses correctly. Assuming it parses correctly as JSON, try using the square/go-jose library and run jose.ParseSigned on your output and tweak until that passes.

1 Like

What kind of hosting provider did u use exactly?

It is a standalone program, no speciffic provider.
I want to develop a library.

There's quite a few issues in the code.

The main one that is stopping you is pretty simple - you're not actually sending the marshaled buffer to the ACME server.

Yep, this is a PKCS#1v1.5 signature over the JWS signature.

OK, this is the final JWS encapsulation that we need to send over the wire.

Wait what? Perhaps you meant:

    Send(b)

I second the suggestion to use go-square/jose, or copy how golang/x/crypto/acme does it without external dependencies, or use @eggsampler's excellent acme v2 library at GitHub - eggsampler/acme: Go client library implementation for ACME v2 (RFC8555)

1 Like

Yes, i have to send b, err := json.MarshalIndent(encodedACMERequest, “”, " ")

 b, err := json.MarshalIndent(encodedACMERequest, "", " ")

unsigned := Unsign(pubKey, byte(acmeRequest.Signature), signed)
fmt.Println("unsigned", unsigned)
fmt.Println(string(b))
Send(b)

even getting same reponse

{
"type": "urn:ietf:params:acme:error:malformed",
"detail": "Parse error reading JWS",
"status": 400
}

Like I said, that mistake is not the only issue in your code.

Here’s a heavily refactored version that runs successfully.

package main

import (
	"bytes"
	"crypto/rand"
	"crypto/rsa"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"log"
	"math/big"
	"net/http"

	"crypto"
	"crypto/sha256"
	"io/ioutil"
)

type Jwk struct {
	E   string `json:"e"`
	Kty string `json:"kty"`
	N   string `json:"n"`
}

// type Header struct {
// 	Alg string `json:"alg"`
// 	Jwk Jwk    `json:"jwk"`
// }

type Protected struct {
	Alg   string `json:"alg"`
	Jwk   Jwk    `json:"jwk,omitempty"`
	Kid   string `json:"kid,omitempty"`
	Nonce string `json:"nonce"`
	URL   string `json:"url"`
}

type Payload struct {
	TermsOfServiceAgreed bool     `json:"termsOfServiceAgreed"`
	Contact              []string `json:"contact"`
}

type AcmeRequest struct {
	// Header    Header    `json:"-"`
	Protected Protected `json:"protected"`
	Payload   Payload   `json:"payload"`
	Signature string    `json:"signature"`
}

type Signature struct {
	Protected string
	Payload   string
}

func (signature Signature) join() string {

	return fmt.Sprintf("%s.%s", signature.Protected, signature.Payload)
}

type Account struct {
	Status               string   `json:"status"`
	Contact              []string `json:"contact"`
	TermsOfServiceAgreed bool     `json:"termsOfServiceAgreed"`
	Orders               string   `json:"orders"`
}

func Send(b []byte) {
	fmt.Println("req", string(b))
	request, err := http.NewRequest("POST", "https://acme-staging-v02.api.letsencrypt.org/acme/new-acct", bytes.NewBuffer(b))
	if err != nil {
		panic(err)
	}
	request.Header.Set("Content-Type", "application/jose+json")
	request.Header.Set("User-Agent", "Vighnesh-Go v2.0")
	// request.Header.Set("Accept-Language", "en")
	// request.Header.Set("Access-Control-Allow-Origin", "*")

	client := &http.Client{}
	resp, err := client.Do(request)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	body, _ := ioutil.ReadAll(resp.Body)
	fmt.Println("response Body:", string(body))
}

func GetNonce() (string, error) {
	response, err := http.Get("https://acme-staging-v02.api.letsencrypt.org/acme/new-nonce")
	return response.Header["Replay-Nonce"][0], err
}

func main() {

	nonce, _ := GetNonce()
	fmt.Println(nonce)

	privkey, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		log.Printf("failed to generate private key: %s", err)
		return
	}

	pubKey := &privkey.PublicKey
	e := base64URLEncode(big.NewInt(int64(pubKey.E)).Bytes())
	n := base64URLEncode(pubKey.N.Bytes())
	kty := "RSA"

	prot := Protected{}
	prot.Alg = "RS256"
	prot.URL = "https://acme-staging-v02.api.letsencrypt.org/acme/new-acct"
	prot.Jwk.E = e
	prot.Jwk.Kty = kty
	prot.Jwk.N = n
	prot.Nonce = nonce

	payload := &Payload{}

	payload.Contact = []string{"mailto:setdc@gmail.com", "mailto:setdc1@gmail.com"}
	payload.TermsOfServiceAgreed = true

	protectedJson, _ := json.MarshalIndent(prot, "", " ")
	//fmt.Println("protected:", string(protectedJson))

	payloadJson, _ := json.MarshalIndent(payload, "", " ")
	//fmt.Println("payload:", string(payloadJson))

	urlEncodedProtected := base64URLEncode(protectedJson)
	urlEncodedPayload := base64URLEncode(payloadJson)

	sig := Signature{urlEncodedProtected, urlEncodedPayload}.join()

	var encoded struct {
		Protected string `json:"protected"`
		Payload   string `json:"payload"`
		Signature string `json:"signature"`
	}

	signed, signError := Sign(privkey, []byte(sig))
	if signError != nil {
		fmt.Println("Could not sign", signError)
	}
	signature := base64URLEncode(signed)

	encoded.Protected = urlEncodedProtected
	encoded.Payload = urlEncodedPayload
	encoded.Signature = signature

	b, err := json.MarshalIndent(encoded, "", " ")

	Send(b)
}

func Sign(privateKey *rsa.PrivateKey, data []byte) ([]byte, error) {
	sha := sha256.New()
	sha.Write(data)
	sha256Hash := sha.Sum(nil)
	return privateKey.Sign(rand.Reader, sha256Hash, crypto.SHA256)
}

// Unsign verifies the message using a rsa-sha256 signature
func Unsign(publicKey *rsa.PublicKey, message []byte, signed []byte) error {
	sha := sha256.New()
	sha.Write(message)
	sha256Hash := sha.Sum(nil)
	return rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, sha256Hash, signed)
}

func base64URLEncode(data []byte) string {
	return base64.RawURLEncoding.EncodeToString(data)
}

func base64URLDecode(data string) ([]byte, error) {
	return base64.RawURLEncoding.DecodeString(data)
}

Thank You, it is working
:grinning:

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