Skip to content

Commit d65422f

Browse files
committed
torchwood: add NewCosignatureVerifier
1 parent c485592 commit d65422f

2 files changed

Lines changed: 57 additions & 0 deletions

File tree

cosignature.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"errors"
1414
"fmt"
1515
"math"
16+
"strconv"
1617
"strings"
1718
"time"
1819
"unicode"
@@ -114,6 +115,48 @@ type CosignatureVerifier struct {
114115

115116
var _ note.Verifier = &CosignatureVerifier{}
116117

118+
// NewCosignatureVerifier constructs a new [CosignatureVerifier] from a
119+
// c2sp.org/signed-note vkey string.
120+
func NewCosignatureVerifier(vkey string) (*CosignatureVerifier, error) {
121+
name, vkey, _ := strings.Cut(vkey, "+")
122+
hash16, key64, _ := strings.Cut(vkey, "+")
123+
hash, err1 := strconv.ParseUint(hash16, 16, 32)
124+
key, err2 := base64.StdEncoding.DecodeString(key64)
125+
if len(hash16) != 8 || err1 != nil || err2 != nil || !isValidName(name) || len(key) == 0 {
126+
return nil, errors.New("malformed verifier id")
127+
}
128+
if uint32(hash) != keyHash(name, key) {
129+
return nil, errors.New("invalid verifier hash")
130+
}
131+
alg, key := key[0], key[1:]
132+
if alg != algCosignatureV1 {
133+
return nil, errors.New("unknown verifier algorithm")
134+
}
135+
if len(key) != ed25519.PublicKeySize {
136+
return nil, errors.New("malformed verifier public key")
137+
}
138+
k := ed25519.PublicKey(key)
139+
return &CosignatureVerifier{
140+
verifier: verifier{
141+
name: name,
142+
hash: uint32(hash),
143+
verify: func(msg, sig []byte) bool {
144+
if len(sig) != 8+ed25519.SignatureSize {
145+
return false
146+
}
147+
t := binary.BigEndian.Uint64(sig)
148+
sig = sig[8:]
149+
m, err := formatCosignatureV1(t, msg)
150+
if err != nil {
151+
return false
152+
}
153+
return ed25519.Verify(k, m, sig)
154+
},
155+
},
156+
key: key,
157+
}, nil
158+
}
159+
117160
// String returns the vkey encoding of the verifier, according to
118161
// c2sp.org/signed-note.
119162
func (v *CosignatureVerifier) String() string {

cosignature_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,18 @@ func TestSignerRoundtrip(t *testing.T) {
3535
if _, err := note.Open(nn, note.VerifierList(s.Verifier())); err == nil {
3636
t.Fatal("expected error verifying modified note, got nil")
3737
}
38+
39+
v, err := torchwood.NewCosignatureVerifier(s.Verifier().String())
40+
if err != nil {
41+
t.Fatal(err)
42+
}
43+
if v.Name() != "example.com" {
44+
t.Fatalf("verifier name = %q; want %q", v.Name(), "example.com")
45+
}
46+
if v.KeyHash() != s.Verifier().KeyHash() {
47+
t.Fatalf("verifier hash = %d; want %d", v.KeyHash(), s.Verifier().KeyHash())
48+
}
49+
if _, err := note.Open(n, note.VerifierList(v)); err != nil {
50+
t.Fatal(err)
51+
}
3852
}

0 commit comments

Comments
 (0)