tka,types/key: remove dependency for tailcfg & types/ packages on tka

Following the pattern elsewhere, we create a new tka-specific types package for the types
that need to couple between the serialized structure types, and tka.

Signed-off-by: Tom DNetto <tom@tailscale.com>
pull/5301/head
Tom DNetto 2 years ago committed by Tom
parent a9f6cd41fd
commit f50043f6cb

@ -1,13 +1,9 @@
tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/depaware)
filippo.io/edwards25519 from github.com/hdevalence/ed25519consensus
filippo.io/edwards25519/field from filippo.io/edwards25519
W 💣 github.com/alexbrainman/sspi from github.com/alexbrainman/sspi/negotiate+
W github.com/alexbrainman/sspi/internal/common from github.com/alexbrainman/sspi/negotiate
W 💣 github.com/alexbrainman/sspi/negotiate from tailscale.com/net/tshttpproxy
github.com/fxamacker/cbor/v2 from tailscale.com/tka
github.com/golang/groupcache/lru from tailscale.com/net/dnscache
github.com/hdevalence/ed25519consensus from tailscale.com/tka
L github.com/josharian/native from github.com/mdlayher/netlink+
L 💣 github.com/jsimonetti/rtnetlink from tailscale.com/net/interfaces
L github.com/jsimonetti/rtnetlink/internal/unix from github.com/jsimonetti/rtnetlink
@ -30,7 +26,6 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
github.com/tailscale/goupnp/ssdp from github.com/tailscale/goupnp
github.com/tcnksm/go-httpstat from tailscale.com/net/netcheck
github.com/toqueteos/webbrowser from tailscale.com/cmd/tailscale/cli
github.com/x448/float16 from github.com/fxamacker/cbor/v2
💣 go4.org/mem from tailscale.com/derp+
go4.org/netipx from tailscale.com/wgengine/filter
W 💣 golang.zx2c4.com/wireguard/windows/tunnel/winipcfg from tailscale.com/net/interfaces+
@ -73,7 +68,6 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
tailscale.com/safesocket from tailscale.com/cmd/tailscale/cli+
tailscale.com/syncs from tailscale.com/net/netcheck+
tailscale.com/tailcfg from tailscale.com/cmd/tailscale/cli+
tailscale.com/tka from tailscale.com/types/key
W tailscale.com/tsconst from tailscale.com/net/interfaces
💣 tailscale.com/tstime/mono from tailscale.com/tstime/rate
tailscale.com/tstime/rate from tailscale.com/wgengine/filter
@ -89,6 +83,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
tailscale.com/types/persist from tailscale.com/ipn
tailscale.com/types/preftype from tailscale.com/cmd/tailscale/cli+
tailscale.com/types/structs from tailscale.com/ipn+
tailscale.com/types/tkatype from tailscale.com/types/key
tailscale.com/types/views from tailscale.com/tailcfg+
tailscale.com/util/clientmetric from tailscale.com/net/netcheck+
tailscale.com/util/cloudenv from tailscale.com/net/dnscache+
@ -102,9 +97,8 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
tailscale.com/version from tailscale.com/cmd/tailscale/cli+
tailscale.com/version/distro from tailscale.com/cmd/tailscale/cli+
tailscale.com/wgengine/filter from tailscale.com/types/netmap
golang.org/x/crypto/argon2 from tailscale.com/tka
golang.org/x/crypto/blake2b from golang.org/x/crypto/nacl/box+
golang.org/x/crypto/blake2s from tailscale.com/control/controlbase+
golang.org/x/crypto/blake2b from golang.org/x/crypto/nacl/box
golang.org/x/crypto/blake2s from tailscale.com/control/controlbase
golang.org/x/crypto/chacha20 from golang.org/x/crypto/chacha20poly1305
golang.org/x/crypto/chacha20poly1305 from crypto/tls+
golang.org/x/crypto/cryptobyte from crypto/ecdsa+
@ -162,7 +156,6 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
embed from tailscale.com/cmd/tailscale/cli+
encoding from encoding/json+
encoding/asn1 from crypto/x509+
encoding/base32 from tailscale.com/tka
encoding/base64 from encoding/json+
encoding/binary from compress/gzip+
encoding/hex from crypto/x509+

@ -244,7 +244,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/syncs from tailscale.com/net/netcheck+
tailscale.com/tailcfg from tailscale.com/client/tailscale/apitype+
LD tailscale.com/tempfork/gliderlabs/ssh from tailscale.com/ssh/tailssh
tailscale.com/tka from tailscale.com/types/key+
tailscale.com/tka from tailscale.com/ipn/ipnlocal+
W tailscale.com/tsconst from tailscale.com/net/interfaces
tailscale.com/tstime from tailscale.com/wgengine/magicsock
💣 tailscale.com/tstime/mono from tailscale.com/net/tstun+
@ -263,6 +263,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/types/persist from tailscale.com/control/controlclient+
tailscale.com/types/preftype from tailscale.com/ipn+
tailscale.com/types/structs from tailscale.com/control/controlclient+
tailscale.com/types/tkatype from tailscale.com/tka+
tailscale.com/types/views from tailscale.com/ipn/ipnlocal+
tailscale.com/util/clientmetric from tailscale.com/control/controlclient+
tailscale.com/util/cloudenv from tailscale.com/net/dns/resolver+

@ -12,15 +12,12 @@ import (
"github.com/fxamacker/cbor/v2"
"golang.org/x/crypto/blake2s"
"tailscale.com/types/tkatype"
)
// AUMHash represents the BLAKE2s digest of an Authority Update Message (AUM).
type AUMHash [blake2s.Size]byte
// AUMSigHash represents the BLAKE2s digest of an Authority Update
// Message (AUM), sans any signatures.
type AUMSigHash [blake2s.Size]byte
// AUMKind describes valid AUM types.
type AUMKind uint8
@ -100,7 +97,7 @@ type AUM struct {
// KeyID references a public key which is part of the key authority.
// This field is used for RemoveKey and UpdateKey AUMs.
KeyID KeyID `cbor:"4,keyasint,omitempty"`
KeyID tkatype.KeyID `cbor:"4,keyasint,omitempty"`
// State describes the full state of the key authority.
// This field is used for Checkpoint AUMs.
@ -118,7 +115,7 @@ type AUM struct {
// Signatures lists the signatures over this AUM.
// CBOR key 23 is the last key which can be encoded as a single byte.
Signatures []Signature `cbor:"23,keyasint,omitempty"`
Signatures []tkatype.Signature `cbor:"23,keyasint,omitempty"`
}
// StaticValidate returns a nil error if the AUM is well-formed.
@ -230,7 +227,7 @@ func (a *AUM) Hash() AUMHash {
// This is identical to Hash() except the Signatures are not
// serialized. Without this, the hash used for signatures
// would be circularly dependent on the signatures.
func (a AUM) SigHash() AUMSigHash {
func (a AUM) SigHash() tkatype.AUMSigHash {
dupe := a
dupe.Signatures = nil
return blake2s.Sum256(dupe.Serialize())
@ -250,7 +247,7 @@ func (a *AUM) sign25519(priv ed25519.PrivateKey) {
key := Key{Kind: Key25519, Public: priv.Public().(ed25519.PublicKey)}
sigHash := a.SigHash()
a.Signatures = append(a.Signatures, Signature{
a.Signatures = append(a.Signatures, tkatype.Signature{
KeyID: key.ID(),
Signature: ed25519.Sign(priv, sigHash[:]),
})

@ -11,6 +11,7 @@ import (
"github.com/fxamacker/cbor/v2"
"github.com/google/go-cmp/cmp"
"golang.org/x/crypto/blake2s"
"tailscale.com/types/tkatype"
)
func TestSerialization(t *testing.T) {
@ -137,7 +138,7 @@ func TestSerialization(t *testing.T) {
},
{
"Signature",
AUM{MessageKind: AUMAddKey, Signatures: []Signature{{KeyID: []byte{1}}}},
AUM{MessageKind: AUMAddKey, Signatures: []tkatype.Signature{{KeyID: []byte{1}}}},
[]byte{
0xa3, // major type 5 (map), 3 items
0x01, // |- major type 0 (int), value 1 (first key, MessageKind)
@ -198,7 +199,7 @@ func TestAUMWeight(t *testing.T) {
{
"Key unknown",
AUM{
Signatures: []Signature{{KeyID: fakeKeyID[:]}},
Signatures: []tkatype.Signature{{KeyID: fakeKeyID[:]}},
},
State{},
0,
@ -206,7 +207,7 @@ func TestAUMWeight(t *testing.T) {
{
"Unary key",
AUM{
Signatures: []Signature{{KeyID: key.ID()}},
Signatures: []tkatype.Signature{{KeyID: key.ID()}},
},
State{
Keys: []Key{key},
@ -216,7 +217,7 @@ func TestAUMWeight(t *testing.T) {
{
"Multiple keys",
AUM{
Signatures: []Signature{{KeyID: key.ID()}, {KeyID: key2.ID()}},
Signatures: []tkatype.Signature{{KeyID: key.ID()}, {KeyID: key2.ID()}},
},
State{
Keys: []Key{key, key2},
@ -226,7 +227,7 @@ func TestAUMWeight(t *testing.T) {
{
"Double use",
AUM{
Signatures: []Signature{{KeyID: key.ID()}, {KeyID: key.ID()}},
Signatures: []tkatype.Signature{{KeyID: key.ID()}, {KeyID: key.ID()}},
},
State{
Keys: []Key{key},
@ -255,7 +256,7 @@ func TestAUMHashes(t *testing.T) {
sigHash1 := aum.SigHash()
aumHash1 := aum.Hash()
aum.Signatures = []Signature{{KeyID: []byte{1, 2, 3, 4}}}
aum.Signatures = []tkatype.Signature{{KeyID: []byte{1, 2, 3, 4}}}
sigHash2 := aum.SigHash()
aumHash2 := aum.Hash()
if len(aum.Signatures) != 1 {

@ -6,11 +6,13 @@ package tka
import (
"fmt"
"tailscale.com/types/tkatype"
)
// Types implementing Signer can sign update messages.
type Signer interface {
SignAUM(*AUM) error
SignAUM(tkatype.AUMSigHash) ([]tkatype.Signature, error)
}
// UpdateBuilder implements a builder for changes to the tailnet
@ -34,9 +36,11 @@ func (b *UpdateBuilder) mkUpdate(update AUM) error {
update.PrevAUMHash = prevHash
if b.signer != nil {
if err := b.signer.SignAUM(&update); err != nil {
sigs, err := b.signer.SignAUM(update.SigHash())
if err != nil {
return fmt.Errorf("signing failed: %v", err)
}
update.Signatures = append(update.Signatures, sigs...)
}
if err := update.StaticValidate(); err != nil {
return fmt.Errorf("generated update was invalid: %v", err)
@ -61,7 +65,7 @@ func (b *UpdateBuilder) AddKey(key Key) error {
}
// RemoveKey removes a key from the authority.
func (b *UpdateBuilder) RemoveKey(keyID KeyID) error {
func (b *UpdateBuilder) RemoveKey(keyID tkatype.KeyID) error {
if _, err := b.state.GetKey(keyID); err != nil {
return fmt.Errorf("failed reading key %x: %v", keyID, err)
}
@ -69,7 +73,7 @@ func (b *UpdateBuilder) RemoveKey(keyID KeyID) error {
}
// SetKeyVote updates the number of votes of an existing key.
func (b *UpdateBuilder) SetKeyVote(keyID KeyID, votes uint) error {
func (b *UpdateBuilder) SetKeyVote(keyID tkatype.KeyID, votes uint) error {
if _, err := b.state.GetKey(keyID); err != nil {
return fmt.Errorf("failed reading key %x: %v", keyID, err)
}
@ -80,7 +84,7 @@ func (b *UpdateBuilder) SetKeyVote(keyID KeyID, votes uint) error {
//
// TODO(tom): Provide an API to update specific values rather than the whole
// map.
func (b *UpdateBuilder) SetKeyMeta(keyID KeyID, meta map[string]string) error {
func (b *UpdateBuilder) SetKeyMeta(keyID tkatype.KeyID, meta map[string]string) error {
if _, err := b.state.GetKey(keyID); err != nil {
return fmt.Errorf("failed reading key %x: %v", keyID, err)
}

@ -9,13 +9,19 @@ import (
"testing"
"github.com/google/go-cmp/cmp"
"tailscale.com/types/tkatype"
)
type signer25519 ed25519.PrivateKey
func (s signer25519) SignAUM(update *AUM) error {
update.sign25519(ed25519.PrivateKey(s))
return nil
func (s signer25519) SignAUM(sigHash tkatype.AUMSigHash) ([]tkatype.Signature, error) {
priv := ed25519.PrivateKey(s)
key := Key{Kind: Key25519, Public: priv.Public().(ed25519.PublicKey)}
return []tkatype.Signature{{
KeyID: key.ID(),
Signature: ed25519.Sign(priv, sigHash[:]),
}}, nil
}
func TestAuthorityBuilderAddKey(t *testing.T) {

@ -15,6 +15,7 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"tailscale.com/types/tkatype"
)
// chaintest_test.go implements test helpers for concisely describing
@ -265,7 +266,7 @@ func (c *testChain) makeAUM(v *testchainNode) AUM {
sigHash := aum.SigHash()
for _, key := range c.SignAllKeys {
aum.Signatures = append(aum.Signatures, Signature{
aum.Signatures = append(aum.Signatures, tkatype.Signature{
KeyID: c.Key[key].ID(),
Signature: ed25519.Sign(c.KeyPrivs[key], sigHash[:]),
})
@ -274,7 +275,7 @@ func (c *testChain) makeAUM(v *testchainNode) AUM {
// If the aum was specified as being signed by some key, then
// sign it using that key.
if key := v.SignedWith; key != "" {
aum.Signatures = append(aum.Signatures, Signature{
aum.Signatures = append(aum.Signatures, tkatype.Signature{
KeyID: c.Key[key].ID(),
Signature: ed25519.Sign(c.KeyPrivs[key], sigHash[:]),
})

@ -10,6 +10,7 @@ import (
"fmt"
"github.com/hdevalence/ed25519consensus"
"tailscale.com/types/tkatype"
)
// KeyKind describes the different varieties of a Key.
@ -73,12 +74,12 @@ func (k Key) Clone() Key {
return out
}
func (k Key) ID() KeyID {
func (k Key) ID() tkatype.KeyID {
switch k.Kind {
// Because 25519 public keys are so short, we just use the 32-byte
// public as their 'key ID'.
case Key25519:
return KeyID(k.Public)
return tkatype.KeyID(k.Public)
default:
panic("unsupported key kind")
}
@ -112,21 +113,9 @@ func (k Key) StaticValidate() error {
return nil
}
// KeyID references a verification key stored in the key authority.
//
// For 25519 keys: The 32-byte public key.
type KeyID []byte
// Signature describes a signature over an AUM, which can be verified
// using the key referenced by KeyID.
type Signature struct {
KeyID KeyID `cbor:"1,keyasint"`
Signature []byte `cbor:"2,keyasint"`
}
// Verify returns a nil error if the signature is valid over the
// provided AUM BLAKE2s digest, using the given key.
func (s *Signature) Verify(aumDigest AUMSigHash, key Key) error {
func signatureVerify(s *tkatype.Signature, aumDigest tkatype.AUMSigHash, key Key) error {
// NOTE(tom): Even if we can compute the public from the KeyID,
// its possible for the KeyID to be attacker-controlled
// so we should use the public contained in the state machine.

@ -10,6 +10,8 @@ import (
"encoding/binary"
"math/rand"
"testing"
"tailscale.com/types/tkatype"
)
// returns a random source based on the test name + extraSeed.
@ -41,24 +43,24 @@ func TestVerify25519(t *testing.T) {
MessageKind: AUMRemoveKey,
KeyID: []byte{1, 2, 3, 4},
// Signatures is set to crap so we are sure its ignored in the sigHash computation.
Signatures: []Signature{{KeyID: []byte{45, 42}}},
Signatures: []tkatype.Signature{{KeyID: []byte{45, 42}}},
}
sigHash := aum.SigHash()
aum.Signatures = []Signature{
aum.Signatures = []tkatype.Signature{
{
KeyID: key.ID(),
Signature: ed25519.Sign(priv, sigHash[:]),
},
}
if err := aum.Signatures[0].Verify(aum.SigHash(), key); err != nil {
if err := signatureVerify(&aum.Signatures[0], aum.SigHash(), key); err != nil {
t.Errorf("signature verification failed: %v", err)
}
// Make sure it fails with a different public key.
pub2, _ := testingKey25519(t, 2)
key2 := Key{Kind: Key25519, Public: pub2}
if err := aum.Signatures[0].Verify(aum.SigHash(), key2); err == nil {
if err := signatureVerify(&aum.Signatures[0], aum.SigHash(), key2); err == nil {
t.Error("signature verification with different key did not fail")
}
}

@ -204,7 +204,7 @@ func TestScenarioHelpers(t *testing.T) {
if _, ok := n.AUMs["L3"]; !ok {
t.Errorf("node n is missing %s", "L3")
}
if err := n.AUMs["L3"].Signatures[0].Verify(n.AUMs["L3"].SigHash(), *s.defaultKey); err != nil {
if err := signatureVerify(&n.AUMs["L3"].Signatures[0], n.AUMs["L3"].SigHash(), *s.defaultKey); err != nil {
t.Errorf("chained AUM was not signed: %v", err)
}

@ -13,6 +13,7 @@ import (
"github.com/fxamacker/cbor/v2"
"github.com/hdevalence/ed25519consensus"
"golang.org/x/crypto/blake2s"
"tailscale.com/types/tkatype"
)
// SigKind describes valid NodeKeySignature types.
@ -67,7 +68,7 @@ func (s NodeKeySignature) sigHash() [blake2s.Size]byte {
}
// Serialize returns the given NKS in a serialized format.
func (s *NodeKeySignature) Serialize() []byte {
func (s *NodeKeySignature) Serialize() tkatype.MarshaledSignature {
out := bytes.NewBuffer(make([]byte, 0, 128)) // 64byte sig + 32byte keyID + 32byte headroom
encoder, err := cbor.CTAP2EncOptions().EncMode()
if err != nil {

@ -10,6 +10,7 @@ import (
"fmt"
"golang.org/x/crypto/argon2"
"tailscale.com/types/tkatype"
)
// ErrNoSuchKey is returned if the key referenced by a KeyID does not exist.
@ -40,7 +41,7 @@ type State struct {
}
// GetKey returns the trusted key with the specified KeyID.
func (s State) GetKey(key KeyID) (Key, error) {
func (s State) GetKey(key tkatype.KeyID) (Key, error) {
for _, k := range s.Keys {
if bytes.Equal(k.ID(), key) {
return k, nil

@ -13,6 +13,7 @@ import (
"sort"
"github.com/fxamacker/cbor/v2"
"tailscale.com/types/tkatype"
)
// Authority is a Tailnet Key Authority. This type is the main coupling
@ -416,7 +417,7 @@ func aumVerify(aum AUM, state State, isGenesisAUM bool) error {
if err != nil {
return fmt.Errorf("bad keyID on signature %d: %v", i, err)
}
if err := sig.Verify(sigHash, key); err != nil {
if err := signatureVerify(&sig, sigHash, key); err != nil {
return fmt.Errorf("signature %d: %v", i, err)
}
}
@ -485,9 +486,11 @@ func Create(storage Chonk, state State, signer Signer) (*Authority, AUM, error)
// This serves as an easy way to validate the given state.
return nil, AUM{}, fmt.Errorf("invalid state: %v", err)
}
if err := signer.SignAUM(&genesis); err != nil {
sigs, err := signer.SignAUM(genesis.SigHash())
if err != nil {
return nil, AUM{}, fmt.Errorf("signing failed: %v", err)
}
genesis.Signatures = append(genesis.Signatures, sigs...)
a, err := Bootstrap(storage, genesis)
return a, genesis, err
@ -591,7 +594,7 @@ func (a *Authority) Inform(updates []AUM) error {
// VerifySignature returns true if the provided nodeKeySignature is signed
// correctly by a trusted key.
func (a *Authority) VerifySignature(nodeKeySignature []byte) error {
func (a *Authority) VerifySignature(nodeKeySignature tkatype.MarshaledSignature) error {
var decoded NodeKeySignature
if err := cbor.Unmarshal(nodeKeySignature, &decoded); err != nil {
return fmt.Errorf("unmarshal: %v", err)

@ -9,6 +9,7 @@ import (
"testing"
"github.com/google/go-cmp/cmp"
"tailscale.com/types/tkatype"
)
func TestComputeChainCandidates(t *testing.T) {
@ -232,7 +233,7 @@ func TestOpenAuthority(t *testing.T) {
i2, i2H := fakeAUM(t, 2, &i1H)
i3, i3H := fakeAUM(t, 5, &i2H)
l2, l2H := fakeAUM(t, AUM{MessageKind: AUMNoOp, KeyID: []byte{7}, Signatures: []Signature{{KeyID: key.ID()}}}, &i3H)
l2, l2H := fakeAUM(t, AUM{MessageKind: AUMNoOp, KeyID: []byte{7}, Signatures: []tkatype.Signature{{KeyID: key.ID()}}}, &i3H)
l3, l3H := fakeAUM(t, 4, &i3H)
g2, g2H := fakeAUM(t, 8, nil)

@ -9,8 +9,8 @@ import (
"crypto/subtle"
"go4.org/mem"
"tailscale.com/tka"
"tailscale.com/types/structs"
"tailscale.com/types/tkatype"
)
const (
@ -68,23 +68,26 @@ func (k NLPrivate) Public() NLPublic {
}
// KeyID returns an identifier for this key.
func (k NLPrivate) KeyID() tka.KeyID {
pub := k.Public()
return tka.Key{
Kind: tka.Key25519,
Public: pub.k[:],
}.ID()
func (k NLPrivate) KeyID() tkatype.KeyID {
// The correct way to compute this is:
// return tka.Key{
// Kind: tka.Key25519,
// Public: pub.k[:],
// }.ID()
//
// However, under the hood the key id for a 25519
// key is just the public key, so we avoid the
// dependency on tka by just doing this ourselves.
pub := k.Public().k
return pub[:]
}
// SignAUM implements tka.UpdateSigner.
func (k NLPrivate) SignAUM(a *tka.AUM) error {
sigHash := a.SigHash()
a.Signatures = append(a.Signatures, tka.Signature{
func (k NLPrivate) SignAUM(sigHash tkatype.AUMSigHash) ([]tkatype.Signature, error) {
return []tkatype.Signature{{
KeyID: k.KeyID(),
Signature: ed25519.Sign(k.k[:], sigHash[:]),
})
return nil
Signature: ed25519.Sign(ed25519.PrivateKey(k.k[:]), sigHash[:]),
}}, nil
}
// NLPublic is the public portion of a a NLPrivate.

@ -6,6 +6,7 @@ package key
import (
"bytes"
"crypto/ed25519"
"testing"
"tailscale.com/tka"
@ -55,7 +56,14 @@ func TestNLPrivate(t *testing.T) {
if got, want := len(aum.Signatures), 1; got != want {
t.Fatalf("len(signatures) = %d, want %d", got, want)
}
if err := aum.Signatures[0].Verify(aum.SigHash(), k); err != nil {
t.Errorf("signature did not verify: %v", err)
sigHash := aum.SigHash()
if ok := ed25519.Verify(pub.Verifier(), sigHash[:], aum.Signatures[0].Signature); !ok {
t.Error("signature did not verify")
}
// We manually compute the keyID, so make sure its consistent with
// tka.Key.ID().
if !bytes.Equal(k.ID(), p.KeyID()) {
t.Errorf("private.KeyID() & tka KeyID differ: %x != %x", k.ID(), p.KeyID())
}
}

@ -0,0 +1,34 @@
// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package tkatype defines types for working with the tka package.
//
// Do not add extra dependencies to this package unless they are tiny,
// because this package encodes wire types that should be lightweight to use.
package tkatype
// KeyID references a verification key stored in the key authority. A keyID
// uniquely identifies a key. KeyIDs are all 32 bytes.
//
// For 25519 keys: We just use the 32-byte public key.
//
// Even though this is a 32-byte value, we use a byte slice because
// CBOR-encoded byte slices have a different prefix to CBOR-encoded arrays.
// Encoding as a byte slice allows us to change the size in the future if we
// ever need to.
type KeyID []byte
// MarshaledSignature represents a marshaled tka.NodeKeySignature.
type MarshaledSignature []byte
// AUMSigHash represents the BLAKE2s digest of an Authority Update
// Message (AUM), sans any signatures.
type AUMSigHash [32]byte
// Signature describes a signature over an AUM, which can be verified
// using the key referenced by KeyID.
type Signature struct {
KeyID KeyID `cbor:"1,keyasint"`
Signature []byte `cbor:"2,keyasint"`
}

@ -0,0 +1,17 @@
// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package tkatype
import (
"golang.org/x/crypto/blake2s"
"testing"
)
func TestSigHashSize(t *testing.T) {
var sigHash AUMSigHash
if len(sigHash) != blake2s.Size {
t.Errorf("AUMSigHash is wrong size: got %d, want %d", len(sigHash), blake2s.Size)
}
}
Loading…
Cancel
Save