From 67c05fd4a2c5b31c10871eaa8c5dd4c2eed4d2c9 Mon Sep 17 00:00:00 2001 From: Elara6331 Date: Sun, 10 Mar 2024 16:00:30 -0700 Subject: [PATCH] Verify previous names in client --- client.go | 52 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/client.go b/client.go index c09b2f7..e81bf63 100644 --- a/client.go +++ b/client.go @@ -100,11 +100,45 @@ func (c Client) lookup(resource, id string, all bool, dest any) error { pubkeySaved := false pubkey, err := c.GetPubkey(pfdURL.Host) if errors.Is(err, ErrPubkeyNotFound) { - info, _, err := getServerInfo(pfdURL.Scheme, pfdURL.Host) + data, sig, prevSigs, err := getServerInfo(pfdURL.Scheme, pfdURL.Host) if err != nil { return err } + var info serverInfoData + err = json.Unmarshal(data, &info) + if err != nil { + return err + } + + // If this server is advertising previous names, make sure + // we verify that it's telling the truth by checking the whether + // any of its signatures match using the pubkeys of the previous names. + if len(info.PreviousNames) > 0 { + for _, prevName := range info.PreviousNames { + pubkey, err = c.GetPubkey(prevName) + if errors.Is(err, ErrPubkeyNotFound) { + continue + } else if err != nil { + return err + } + + if ed25519.Verify(pubkey, data, sig) { + break + } + + for _, prevSig := range prevSigs { + if ed25519.Verify(pubkey, data, prevSig) { + break + } + } + + // If we haven't broken out of the loop by now, this + // name could not be verified, so return an error. + return ErrSignatureMismatch + } + } + pubkey, err = base64.StdEncoding.DecodeString(info.PublicKey) if err != nil { return err @@ -229,20 +263,24 @@ func serverInfoReq(scheme, host string) (*http.Response, error) { } // getServerInfo retrieves server information. -func getServerInfo(scheme, host string) (serverInfoData, [][]byte, error) { +func getServerInfo(scheme, host string) (data, sig []byte, prevSigs [][]byte, err error) { res, err := serverInfoReq(scheme, host) if err != nil { - return serverInfoData{}, nil, err + return nil, nil, nil, err } defer res.Body.Close() if err := checkResp(res, "getServerInfo"); err != nil { - return serverInfoData{}, nil, err + return nil, nil, nil, err } - var out serverInfoData - err = json.NewDecoder(io.LimitReader(res.Body, responseSizeLimit)).Decode(&out) - return out, getPrevSignatures(res), err + sig, err = getSignature(res) + if err != nil { + return nil, nil, nil, err + } + + data, err = io.ReadAll(io.LimitReader(res.Body, responseSizeLimit)) + return data, sig, getPrevSignatures(res), err } // getPrevSignatures extracts previous signatures from a response.