diff options
Diffstat (limited to 'pkg/types')
| -rw-r--r-- | pkg/types/encoding.go | 31 | ||||
| -rw-r--r-- | pkg/types/encoding_test.go | 63 | ||||
| -rw-r--r-- | pkg/types/leaf.go | 13 | ||||
| -rw-r--r-- | pkg/types/leaf_test.go | 15 | ||||
| -rw-r--r-- | pkg/types/tree_head.go | 28 | ||||
| -rw-r--r-- | pkg/types/tree_head_test.go | 13 | 
6 files changed, 145 insertions, 18 deletions
| diff --git a/pkg/types/encoding.go b/pkg/types/encoding.go new file mode 100644 index 0000000..54a1ac6 --- /dev/null +++ b/pkg/types/encoding.go @@ -0,0 +1,31 @@ +package types + +import ( +	"encoding/binary" +	"fmt" +) + +// RFC4251, section 5 + +func putSSHString(b []byte, str string) int { +	l := len(str) + +	i := 0 +	binary.BigEndian.PutUint32(b[i:i+4], uint32(l)) +	i += 4 +	copy(b[i:i+l], str) +	i += l + +	return i +} + +func getSSHString(b []byte) (*string, error) { +	if len(b) < 4 { +		return nil, fmt.Errorf("types: invalid SSH string") +	} + +	l := binary.BigEndian.Uint32(b[:4]) +	str := string(b[4 : 4+l]) +	return &str, nil + +} diff --git a/pkg/types/encoding_test.go b/pkg/types/encoding_test.go new file mode 100644 index 0000000..e079a8c --- /dev/null +++ b/pkg/types/encoding_test.go @@ -0,0 +1,63 @@ +package types + +import ( +	"bytes" +	"testing" +) + +func TestPutSSHString(t *testing.T) { +	for _, tbl := range []struct { +		desc string +		in   string +	}{ +		{ +			desc: "valid", +			in:   "รถ foo is a bar", +		}, +	} { +		var b [128]byte +		i := putSSHString(b[:], tbl.in) + +		if got, want := i, len(tbl.in)+4; got != want { +			t.Errorf("%q: len: got %d but wanted %d in test", tbl.desc, got, want) +		} + +		if got, want := b[4:4+len(tbl.in)], []byte(tbl.in); !bytes.Equal(got, want) { +			t.Errorf("%q: got %x but wanted %x", tbl.desc, got, want) +		} +	} +} + +func TestGetSSHString(t *testing.T) { +	for _, tbl := range []struct { +		desc    string +		in      []byte +		want    string +		wantErr bool +	}{ +		{ +			desc: "valid", +			in:   []byte{0, 0, 0, 5, 65, 108, 108, 97, 110}, +			want: "Allan", +		}, +		{ +			desc:    "invalid: short", +			in:      []byte{0, 0, 0}, +			wantErr: true, +		}, +	} { +		str, err := getSSHString(tbl.in) + +		if got, want := err != nil, tbl.wantErr; got != want { +			t.Errorf("%q: error: got %v but wanted %v: %v", tbl.desc, got, want, err) +		} + +		if err != nil { +			continue +		} + +		if got, want := str, tbl.want; *got != want { +			t.Errorf(`%q: got "%v" but wanted "%v"`, tbl.desc, *got, want) +		} +	} +} diff --git a/pkg/types/leaf.go b/pkg/types/leaf.go index 1476ead..e7e81dd 100644 --- a/pkg/types/leaf.go +++ b/pkg/types/leaf.go @@ -24,9 +24,16 @@ type Leaf struct {  type Leaves []Leaf  func (s *Statement) ToBinary() []byte { -	b := make([]byte, 40) -	binary.BigEndian.PutUint64(b[0:8], s.ShardHint) -	copy(b[8:40], s.Checksum[:]) +	namespace := fmt.Sprintf("tree_leaf:v0:%d@sigsum.org", s.ShardHint) +	b := make([]byte, 6+4+len(namespace)+4+0+4+6+4+HashSize) + +	copy(b[0:6], "SSHSIG") +	i := 6 +	i += putSSHString(b[i:], namespace) +	i += putSSHString(b[i:], "") +	i += putSSHString(b[i:], "sha256") +	i += putSSHString(b[i:], string(s.Checksum[:])) +  	return b  } diff --git a/pkg/types/leaf_test.go b/pkg/types/leaf_test.go index 00e8256..645f49e 100644 --- a/pkg/types/leaf_test.go +++ b/pkg/types/leaf_test.go @@ -223,14 +223,17 @@ func TestLeavesFromASCII(t *testing.T) {  func validStatement(t *testing.T) *Statement {  	return &Statement{  		ShardHint: 72623859790382856, -		Checksum:  *newHashBufferInc(t), +		Checksum:  *HashFn(newHashBufferInc(t)[:]),  	}  }  func validStatementBytes(t *testing.T) []byte {  	return bytes.Join([][]byte{ -		[]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, -		newHashBufferInc(t)[:], +		[]byte("SSHSIG"), +		[]byte{0, 0, 0, 41}, []byte("tree_leaf:v0:72623859790382856@sigsum.org"), +		[]byte{0, 0, 0, 0}, +		[]byte{0, 0, 0, 6}, []byte("sha256"), +		[]byte{0, 0, 0, 32}, HashFn(newHashBufferInc(t)[:])[:],  	}, nil)  } @@ -238,7 +241,7 @@ func validLeaf(t *testing.T) *Leaf {  	return &Leaf{  		Statement: Statement{  			ShardHint: 72623859790382856, -			Checksum:  *newHashBufferInc(t), +			Checksum:  *HashFn(newHashBufferInc(t)[:]),  		},  		Signature: *newSigBufferInc(t),  		KeyHash:   *newHashBufferInc(t), @@ -248,7 +251,7 @@ func validLeaf(t *testing.T) *Leaf {  func validLeafBytes(t *testing.T) []byte {  	return bytes.Join([][]byte{  		[]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, -		newHashBufferInc(t)[:], +		HashFn(newHashBufferInc(t)[:])[:],  		newSigBufferInc(t)[:],  		newHashBufferInc(t)[:],  	}, nil) @@ -257,7 +260,7 @@ func validLeafBytes(t *testing.T) []byte {  func validLeafASCII(t *testing.T) string {  	return fmt.Sprintf("%s=%d\n%s=%x\n%s=%x\n%s=%x\n",  		"shard_hint", 72623859790382856, -		"checksum", newHashBufferInc(t)[:], +		"checksum", HashFn(newHashBufferInc(t)[:])[:],  		"signature", newSigBufferInc(t)[:],  		"key_hash", newHashBufferInc(t)[:],  	) diff --git a/pkg/types/tree_head.go b/pkg/types/tree_head.go index 0f1efee..b0214ca 100644 --- a/pkg/types/tree_head.go +++ b/pkg/types/tree_head.go @@ -8,6 +8,7 @@ import (  	"io"  	"git.sigsum.org/sigsum-lib-go/pkg/ascii" +	"git.sigsum.org/sigsum-lib-go/pkg/hex"  )  type TreeHead struct { @@ -27,17 +28,30 @@ type CosignedTreeHead struct {  	KeyHash     []Hash      `ascii:"key_hash"`  } -func (th *TreeHead) ToBinary(keyHash *Hash) []byte { -	b := make([]byte, 80) +func (th *TreeHead) toBinary() []byte { +	b := make([]byte, 48)  	binary.BigEndian.PutUint64(b[0:8], th.Timestamp)  	binary.BigEndian.PutUint64(b[8:16], th.TreeSize)  	copy(b[16:48], th.RootHash[:]) -	copy(b[48:80], keyHash[:])  	return b  } -func (th *TreeHead) Sign(s crypto.Signer, ctx *Hash) (*SignedTreeHead, error) { -	sig, err := s.Sign(nil, th.ToBinary(ctx), crypto.Hash(0)) +func (th *TreeHead) ToBinary(keyHash *Hash) []byte { +	namespace := fmt.Sprintf("tree_head:v0:%s@sigsum.org", hex.Serialize((*keyHash)[:])) // length 88 +	b := make([]byte, 6+4+88+4+0+4+6+4+HashSize) + +	copy(b[0:6], "SSHSIG") +	i := 6 +	i += putSSHString(b[i:], namespace) +	i += putSSHString(b[i:], "") +	i += putSSHString(b[i:], "sha256") +	i += putSSHString(b[i:], string((*HashFn(th.toBinary()))[:])) + +	return b +} + +func (th *TreeHead) Sign(s crypto.Signer, kh *Hash) (*SignedTreeHead, error) { +	sig, err := s.Sign(nil, th.ToBinary(kh), crypto.Hash(0))  	if err != nil {  		return nil, fmt.Errorf("types: failed signing tree head")  	} @@ -57,8 +71,8 @@ func (sth *SignedTreeHead) FromASCII(r io.Reader) error {  	return ascii.StdEncoding.Deserialize(r, sth)  } -func (sth *SignedTreeHead) Verify(key *PublicKey, ctx *Hash) bool { -	return ed25519.Verify(ed25519.PublicKey(key[:]), sth.TreeHead.ToBinary(ctx), sth.Signature[:]) +func (sth *SignedTreeHead) Verify(key *PublicKey, kh *Hash) bool { +	return ed25519.Verify(ed25519.PublicKey(key[:]), sth.TreeHead.ToBinary(kh), sth.Signature[:])  }  func (cth *CosignedTreeHead) ToASCII(w io.Writer) error { diff --git a/pkg/types/tree_head_test.go b/pkg/types/tree_head_test.go index 03a52f5..f20afe0 100644 --- a/pkg/types/tree_head_test.go +++ b/pkg/types/tree_head_test.go @@ -7,6 +7,8 @@ import (  	"io"  	"reflect"  	"testing" + +	"git.sigsum.org/sigsum-lib-go/pkg/hex"  )  func TestTreeHeadToBinary(t *testing.T) { @@ -186,11 +188,18 @@ func validTreeHead(t *testing.T) *TreeHead {  }  func validTreeHeadBytes(t *testing.T, keyHash *Hash) []byte { -	return bytes.Join([][]byte{ +	ns := fmt.Sprintf("tree_head:v0:%s@sigsum.org", hex.Serialize((*keyHash)[:])) +	th := bytes.Join([][]byte{  		[]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},  		[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01},  		newHashBufferInc(t)[:], -		keyHash[:], +	}, nil) +	return bytes.Join([][]byte{ +		[]byte("SSHSIG"), +		[]byte{0, 0, 0, 88}, []byte(ns), +		[]byte{0, 0, 0, 0}, +		[]byte{0, 0, 0, 6}, []byte("sha256"), +		[]byte{0, 0, 0, 32}, (*HashFn(th))[:],  	}, nil)  } | 
