1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
package types
import (
"crypto"
"crypto/ed25519"
"encoding/binary"
"fmt"
"io"
"git.sigsum.org/sigsum-go/pkg/ascii"
)
type Statement struct {
ShardHint uint64 `ascii:"shard_hint"`
Checksum Hash `ascii:"checksum"`
}
type Leaf struct {
Statement
Signature Signature `ascii:"signature"`
KeyHash Hash `ascii:"key_hash"`
}
type Leaves []Leaf
func (s *Statement) ToBinary() []byte {
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
}
func (s *Statement) Sign(signer crypto.Signer) (*Signature, error) {
sig, err := signer.Sign(nil, s.ToBinary(), crypto.Hash(0))
if err != nil {
return nil, fmt.Errorf("types: failed signing statement")
}
var signature Signature
copy(signature[:], sig)
return &signature, nil
}
func (s *Statement) Verify(key *PublicKey, sig *Signature) bool {
return ed25519.Verify(ed25519.PublicKey(key[:]), s.ToBinary(), sig[:])
}
func (l *Leaf) ToBinary() []byte {
b := make([]byte, 136)
binary.BigEndian.PutUint64(b[0:8], l.ShardHint)
copy(b[8:40], l.Checksum[:])
copy(b[40:104], l.Signature[:])
copy(b[104:136], l.KeyHash[:])
return b
}
func (l *Leaf) FromBinary(b []byte) error {
if len(b) != 136 {
return fmt.Errorf("types: invalid leaf size: %d", len(b))
}
l.ShardHint = binary.BigEndian.Uint64(b[0:8])
copy(l.Checksum[:], b[8:40])
copy(l.Signature[:], b[40:104])
copy(l.KeyHash[:], b[104:136])
return nil
}
func (l *Leaf) ToASCII(w io.Writer) error {
return ascii.StdEncoding.Serialize(w, l)
}
func (l *Leaf) FromASCII(r io.Reader) error {
return ascii.StdEncoding.Deserialize(r, l)
}
func (l *Leaves) FromASCII(r io.Reader) error {
leaves := &struct {
ShardHint []uint64 `ascii:"shard_hint"`
Checksum []Hash `ascii:"checksum"`
Signature []Signature `ascii:"signature"`
KeyHash []Hash `ascii:"key_hash"`
}{}
if err := ascii.StdEncoding.Deserialize(r, leaves); err != nil {
return err
}
n := len(leaves.ShardHint)
if n != len(leaves.Checksum) {
return fmt.Errorf("types: mismatched leaf field counts")
}
if n != len(leaves.Signature) {
return fmt.Errorf("types: mismatched leaf field counts")
}
if n != len(leaves.KeyHash) {
return fmt.Errorf("types: mismatched leaf field counts")
}
*l = make([]Leaf, 0, n)
for i := 0; i < n; i++ {
*l = append(*l, Leaf{
Statement: Statement{
ShardHint: leaves.ShardHint[i],
Checksum: leaves.Checksum[i],
},
Signature: leaves.Signature[i],
KeyHash: leaves.KeyHash[i],
})
}
return nil
}
|