Help needed: Cannot send POST to mastodon inbox, verification issue

I am trying to write an activity pub server with Go.
I am following this tutorial and ap spec. I can find my account, it seems that webfinger is ok, when I try to post to pleroma I get “ok”. But in mastodon there is a verification problem: “Verification failed for […] using rsa-sha256 (RSASSA-PKCS1-v1_5 with SHA-256)”

I have tried to sign my request both with httpsig(go-fed) library and
write it manually. In both cases, I have the same problem.

Here is my code:

        prefs := []httpsig.Algorithm{httpsig.RSA_SHA512, httpsig.RSA_SHA256}
        digestAlgorithm := httpsig.DigestSha256
        headersToSign := []string{httpsig.RequestTarget, "host", "date", "digest", "content-type"}
        postSigner, _, err := httpsig.NewSigner(prefs, digestAlgorithm, headersToSign, httpsig.Signature, 60)

        req, _ := http.NewRequest("POST", to, buf)

        date := fmt.Sprintf("%s GMT", x.UTC().Format("Mon, 02 Jan 2006 15:04:05"))
        pub :=  "example.org/actor#main-key"
        req.Header.Add("Accept", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"")
        req.Header.Add("User-Agent", "example")
        req.Header.Add("Host", iri.Host) // mstdn.social in this case
        req.Header.Add("Date", time.Now().UTC().Format("Mon, 02 Jan 2006 15:04:05")+" GMT")
        req.Header.Add("Content-Type", "application/activity+json; charset=utf-8")
        err = postSigner.SignRequest(get_private(), pub, req,  b)

I have tried to test it with httpsig.NewVerifier and the error is nil.

Here is my actor:

{
        "@context": [
                "https://www.w3.org/ns/activitystreams",
                "https://w3id.org/security/v1"
        ],

        "id": "https://example.org/actor",
        "type": "Person",
        "preferredUsername": "actor",
        "inbox": "https://example.org/actor/inbox",
        "outbox": "https://example.org/actor/outbox",

        "publicKey": {
                "id": "https://example.org/actor#main-key",
          "owner": "https://example.org/actor",
          "publicKeyPem": "-----BEGIN PUBLIC KEY-----\n[long]\n-----END PUBLIC KEY-----\n"
        }
}

and my note:


{
        "@context": "https://www.w3.org/ns/activitystreams",

        "id": "https://example.org/id",
        "type": "Create",
        "actor": "https://example.org/actor",
        "published": "2012-07-29T102:035:07Z",

        "object": {
                "id": "https://example.org/actor/hello",
                "type": "Note",
                "attributedTo": "https://example.org/actor",
                "content": "<p>Hello world</p>",
                "to": "https://www.w3.org/ns/activitystreams#Public"
        }
}

have a look at Help Needed: HTTP Signatures - #25 by mro – and there is a running dash example https://codeberg.org/mro/activitypub/src/branch/master/like.sh

There are numerous oddities in your sample, e.g. first lacks the digest(?) but this may be due to the high level helpers you use. The activity also looks different from what I found working.

thank you, i am reading it now.

i get digest from the library.

he activity also looks different from what I found working.

how?

        signed_string := fmt.Sprintf("(request-target): post /inbox\nhost: %s\ndate: %s", "mstdn.social", date)

        digest := sha256.Sum256([]byte(signed_string))
        signature, _ := rsa.SignPKCS1v15(rand.Reader, priv., crypto.SHA256, digest[:])

        b64sig := base64.StdEncoding.EncodeToString(signature)

        h := sha256.New()
        h.Write(b)
        var header = `keyId="https://picverse.am/complete#main-key",algorithm="rsa-sha256",headers="(request-target) content-type date digest host",signature="` + b64sig + `"`
        req, err := http.NewRequest("POST", to, buf)

        req.Header.Add("Host", iri.Host)
        req.Header.Add("Date", date)
        req.Header.Add("Digest", "SHA-256="+base64.StdEncoding.EncodeToString(h.Sum(nil)))
        req.Header.Add("Content-Type", "application/activity+json")
        req.Header.Add("Content-Type", "application/ld+json")
        req.Header.Add("Content-Type", "application/json; charset=utf-8")
        req.Header.Add("Signature", header)

here is how i have tried to do it manually

sorry, I pasted the wrong link. Look at https://codeberg.org/mro/activitypub/src/commit/4b1319d5363f4a836f23c784ef780b81bc674013/like.sh#L101

1 Like

don’t be confused, happened to me too, though. The digest is over the request body (the json activity) while the signature is over selected request headers plus the pseudo-header (request-target).

I have never before seen multiple content-types. Use application/activity+json only.

And https://picverse.am/complete gives a 502 currently. It must return a profile including the public key, however. A fairly minimal example is https://demo.mro.name/activitypub/u/alice/

1 Like

were you successful meanwhile?

I have done this part today. The digest part was wrong. Now it works! thank you for your answer.

I think http signatures are confusing, maybe we need clarification about it and good documentations because sometimes its unclear how you need to implement it

1 Like

nice to hear things worked out.

indeed, that’s why I made like.sh with no convenience layers but in mere commandline tools.

2 Likes