Skip to content

Commit

Permalink
feat(VerifySigParams): adds VerifySigParams & refactors all signatu…
Browse files Browse the repository at this point in the history
…re logic

moves all signature logic to a new `signature.go` file
Adds a `VerifySigParams` that takes a publicKey, a `params` `map[string]string`, and returns a bool, error. Bool is true if the signature is verified.
  • Loading branch information
ramfox committed Oct 24, 2019
1 parent 3c38191 commit 2c9e3f8
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 57 deletions.
57 changes: 0 additions & 57 deletions remote/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,16 @@ package remote

import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
"time"

coreiface "github.com/ipfs/interface-go-ipfs-core"
crypto "github.com/libp2p/go-libp2p-crypto"
peer "github.com/libp2p/go-libp2p-peer"
"github.com/multiformats/go-multihash"
"github.com/qri-io/dag/dsync"
"github.com/qri-io/dataset/dsfs"
"github.com/qri-io/qfs/cafs"
Expand Down Expand Up @@ -305,60 +302,6 @@ func removeDatasetHTTP(ctx context.Context, params map[string]string, remoteAddr
return nil
}

func sigParams(pk crypto.PrivKey, ref repo.DatasetRef) (map[string]string, error) {

pid, err := calcProfileID(pk)
if err != nil {
return nil, err
}

now := fmt.Sprintf("%d", time.Now().In(time.UTC).Unix())
rss := requestSigningString(now, pid, ref.Path)

b64Sig, err := signString(pk, rss)
if err != nil {
return nil, err
}

return map[string]string{
"peername": ref.Peername,
"name": ref.Name,
"profileID": ref.ProfileID.String(),
"path": ref.Path,

"pid": pid,
"timestamp": now,
"signature": b64Sig,
}, nil
}

func requestSigningString(timestamp, peerID, cidStr string) string {
return fmt.Sprintf("%s.%s.%s", timestamp, peerID, cidStr)
}

func signString(privKey crypto.PrivKey, str string) (b64Sig string, err error) {
sigbytes, err := privKey.Sign([]byte(str))
if err != nil {
return "", fmt.Errorf("error signing %s", err.Error())
}

return base64.StdEncoding.EncodeToString(sigbytes), nil
}

func calcProfileID(privKey crypto.PrivKey) (string, error) {
pubkeybytes, err := privKey.GetPublic().Bytes()
if err != nil {
return "", fmt.Errorf("error getting pubkey bytes: %s", err.Error())
}

mh, err := multihash.Sum(pubkeybytes, multihash.SHA2_256, 32)
if err != nil {
return "", fmt.Errorf("error summing pubkey: %s", err.Error())
}

return mh.B58String(), nil
}

// TODO (b5) - this should return an enumeration
func addressType(remoteAddr string) string {
// if a valid base58 peerID is passed, we're doing a p2p dsync
Expand Down
102 changes: 102 additions & 0 deletions remote/signature.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package remote

import (
"encoding/base64"
"fmt"
"time"

crypto "github.com/libp2p/go-libp2p-crypto"
"github.com/multiformats/go-multihash"
"github.com/qri-io/qri/repo"
)

var (
// nowFunc is an ps function for getting timestamps
nowFunc = time.Now
)

func sigParams(pk crypto.PrivKey, ref repo.DatasetRef) (map[string]string, error) {
pid, err := calcProfileID(pk)
if err != nil {
return nil, err
}

now := fmt.Sprintf("%d", nowFunc().In(time.UTC).Unix())
rss := requestSigningString(now, pid, ref.Path)
b64Sig, err := signString(pk, rss)
if err != nil {
return nil, err
}

return map[string]string{
"peername": ref.Peername,
"name": ref.Name,
"profileID": ref.ProfileID.String(),
"path": ref.Path,

"pid": pid,
"timestamp": now,
"signature": b64Sig,
}, nil
}

// VerifySigParams takes a public key and a map[string]string params and verifies
// the the signature is correct
// TODO (ramfox): should be refactored to be private once remotes have their
// own keystore and can make the replation between a pid and a public key
// on their own
func VerifySigParams(pubkey crypto.PubKey, params map[string]string) (bool, error) {
timestamp, ok := params["timestamp"]
if !ok {
return false, fmt.Errorf("params need key 'timestamp'")
}
pid, ok := params["pid"]
if !ok {
return false, fmt.Errorf("params need key 'pid'")
}
path, ok := params["path"]
if !ok {
return false, fmt.Errorf("params need key 'path'")
}
signature, ok := params["signature"]
if !ok {
return false, fmt.Errorf("params need key 'signature'")
}

sigBytes, err := base64.StdEncoding.DecodeString(signature)
if err != nil {
return false, err
}
str := base64.StdEncoding.EncodeToString(sigBytes)
if str != signature {
return false, fmt.Errorf("signature was '%s', after decode then encode it was '%s", signature, str)
}
rss := requestSigningString(timestamp, pid, path)
return pubkey.Verify([]byte(rss), sigBytes)
}

func requestSigningString(timestamp, peerID, cidStr string) string {
return fmt.Sprintf("%s.%s.%s", timestamp, peerID, cidStr)
}

func signString(privKey crypto.PrivKey, str string) (b64Sig string, err error) {
sigbytes, err := privKey.Sign([]byte(str))
if err != nil {
return "", fmt.Errorf("error signing %s", err.Error())
}
return base64.StdEncoding.EncodeToString(sigbytes), nil
}

func calcProfileID(privKey crypto.PrivKey) (string, error) {
pubkeybytes, err := privKey.GetPublic().Bytes()
if err != nil {
return "", fmt.Errorf("error getting pubkey bytes: %s", err.Error())
}

mh, err := multihash.Sum(pubkeybytes, multihash.SHA2_256, 32)
if err != nil {
return "", fmt.Errorf("error summing pubkey: %s", err.Error())
}

return mh.B58String(), nil
}
41 changes: 41 additions & 0 deletions remote/signature_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package remote

import (
"testing"

"github.com/qri-io/qri/config/test"
"github.com/qri-io/qri/repo"
"github.com/qri-io/qri/repo/profile"
)

func TestVerifySigParams(t *testing.T) {
peerInfo := test.GetTestPeerInfo(0)
pid, err := calcProfileID(peerInfo.PrivKey)
if err != nil {
t.Errorf(err.Error())
return
}
profileID, err := profile.NewB58ID(pid)
if err != nil {
t.Errorf(err.Error())
return
}
ref := repo.DatasetRef{
Path: "foo",
Peername: "bar",
Name: "baz",
ProfileID: profileID,
}
sigParams, err := sigParams(peerInfo.PrivKey, ref)
if err != nil {
panic(err)
}

verified, err := VerifySigParams(peerInfo.PubKey, sigParams)
if err != nil {
t.Errorf("case 'should verify', expected no error, got '%s'", err)
}
if verified == false {
t.Errorf("case 'should verify', expected verification to be true, was false")
}
}

0 comments on commit 2c9e3f8

Please sign in to comment.