[bugfix] Fix http signatures trying to derive actor (#1956)
* add GetResolvedPublicKeyFromIRI * verify public key using key not actor w/key * try most common algos first * try stated algo first * make sure not to try an algo twice * return errors per algorithm * linting
This commit is contained in:
parent
34629d0f5d
commit
05a134c64e
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
@ -71,26 +72,31 @@ func Verify(request *http.Request) (bool, error) {
|
||||
return false, errors.New("Unable to determine algorithm to verify request")
|
||||
}
|
||||
|
||||
actor, err := resolvers.GetResolvedActorFromIRI(pubKeyID.String())
|
||||
publicKey, err := resolvers.GetResolvedPublicKeyFromIRI(pubKeyID.String())
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "failed to resolve actor from IRI to fetch key")
|
||||
}
|
||||
|
||||
if actor.ActorIri == nil {
|
||||
return false, errors.New("actor IRI is empty")
|
||||
var publicKeyActorIRI *url.URL
|
||||
if ownerProp := publicKey.GetW3IDSecurityV1Owner(); ownerProp != nil {
|
||||
publicKeyActorIRI = ownerProp.Get()
|
||||
}
|
||||
|
||||
if publicKeyActorIRI == nil {
|
||||
return false, errors.New("public key owner IRI is empty")
|
||||
}
|
||||
|
||||
// Test to see if the actor is in the list of blocked federated domains.
|
||||
if isBlockedDomain(actor.ActorIri.Hostname()) {
|
||||
if isBlockedDomain(publicKeyActorIRI.Hostname()) {
|
||||
return false, errors.New("domain is blocked")
|
||||
}
|
||||
|
||||
// If actor is specifically blocked, then fail validation.
|
||||
if blocked, err := isBlockedActor(actor.ActorIri); err != nil || blocked {
|
||||
if blocked, err := isBlockedActor(publicKeyActorIRI); err != nil || blocked {
|
||||
return false, err
|
||||
}
|
||||
|
||||
key := actor.W3IDSecurityV1PublicKey.Begin().Get().GetW3IDSecurityV1PublicKeyPem().Get()
|
||||
key := publicKey.GetW3IDSecurityV1PublicKeyPem().Get()
|
||||
block, _ := pem.Decode([]byte(key))
|
||||
if block == nil {
|
||||
log.Errorln("failed to parse PEM block containing the public key")
|
||||
@ -103,14 +109,25 @@ func Verify(request *http.Request) (bool, error) {
|
||||
return false, errors.Wrap(err, "failed to parse DER encoded public key")
|
||||
}
|
||||
|
||||
var algorithm httpsig.Algorithm = httpsig.Algorithm(algorithmString)
|
||||
|
||||
// The verifier will verify the Digest in addition to the HTTP signature
|
||||
if err := verifier.Verify(parsedKey, algorithm); err != nil {
|
||||
return false, errors.Wrap(err, algorithmString+" http signature verification error for: "+pubKeyID.String())
|
||||
algos := []httpsig.Algorithm{
|
||||
httpsig.Algorithm(algorithmString), // try stated algorithm first then other common algorithms
|
||||
httpsig.RSA_SHA256, // <- used by almost all fedi software
|
||||
httpsig.RSA_SHA512,
|
||||
}
|
||||
|
||||
// The verifier will verify the Digest in addition to the HTTP signature
|
||||
triedAlgos := make(map[httpsig.Algorithm]error)
|
||||
for _, algorithm := range algos {
|
||||
if _, tried := triedAlgos[algorithm]; !tried {
|
||||
err := verifier.Verify(parsedKey, algorithm)
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
triedAlgos[algorithm] = err
|
||||
}
|
||||
}
|
||||
|
||||
return false, fmt.Errorf("http signature verification error(s) for: %s: %+v", pubKeyID.String(), triedAlgos)
|
||||
}
|
||||
|
||||
func isBlockedDomain(domain string) bool {
|
||||
|
@ -122,6 +122,72 @@ func GetResolvedActorFromActorProperty(actor vocab.ActivityStreamsActorProperty)
|
||||
return apActor, err
|
||||
}
|
||||
|
||||
// GetResolvedPublicKeyFromIRI will resolve a publicKey IRI string to a vocab.W3IDSecurityV1PublicKey.
|
||||
func GetResolvedPublicKeyFromIRI(publicKeyIRI string) (vocab.W3IDSecurityV1PublicKey, error) {
|
||||
var err error
|
||||
var pubkey vocab.W3IDSecurityV1PublicKey
|
||||
resolved := false
|
||||
|
||||
personCallback := func(c context.Context, person vocab.ActivityStreamsPerson) error {
|
||||
if pkProp := person.GetW3IDSecurityV1PublicKey(); pkProp != nil {
|
||||
for iter := pkProp.Begin(); iter != pkProp.End(); iter = iter.Next() {
|
||||
if iter.IsW3IDSecurityV1PublicKey() {
|
||||
pubkey = iter.Get()
|
||||
resolved = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return errors.New("error deriving publickey from activitystreamsperson")
|
||||
}
|
||||
|
||||
serviceCallback := func(c context.Context, service vocab.ActivityStreamsService) error {
|
||||
if pkProp := service.GetW3IDSecurityV1PublicKey(); pkProp != nil {
|
||||
for iter := pkProp.Begin(); iter != pkProp.End(); iter = iter.Next() {
|
||||
if iter.IsW3IDSecurityV1PublicKey() {
|
||||
pubkey = iter.Get()
|
||||
resolved = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return errors.New("error deriving publickey from activitystreamsservice")
|
||||
}
|
||||
|
||||
applicationCallback := func(c context.Context, app vocab.ActivityStreamsApplication) error {
|
||||
if pkProp := app.GetW3IDSecurityV1PublicKey(); pkProp != nil {
|
||||
for iter := pkProp.Begin(); iter != pkProp.End(); iter = iter.Next() {
|
||||
if iter.IsW3IDSecurityV1PublicKey() {
|
||||
pubkey = iter.Get()
|
||||
resolved = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return errors.New("error deriving publickey from activitystreamsapp")
|
||||
}
|
||||
|
||||
pubkeyCallback := func(c context.Context, pk vocab.W3IDSecurityV1PublicKey) error {
|
||||
pubkey = pk
|
||||
resolved = true
|
||||
return nil
|
||||
}
|
||||
|
||||
if e := ResolveIRI(context.Background(), publicKeyIRI, personCallback, serviceCallback, applicationCallback, pubkeyCallback); e != nil {
|
||||
err = e
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "error resolving publickey from iri")
|
||||
}
|
||||
|
||||
if !resolved {
|
||||
err = errors.New("error resolving publickey from iri")
|
||||
}
|
||||
|
||||
return pubkey, err
|
||||
}
|
||||
|
||||
// GetResolvedActorFromIRI will resolve an IRI string to a fully populated actor.
|
||||
func GetResolvedActorFromIRI(personOrServiceIRI string) (apmodels.ActivityPubActor, error) {
|
||||
var err error
|
||||
|
Loading…
x
Reference in New Issue
Block a user