key.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package tka
  4. import (
  5. "crypto/ed25519"
  6. "errors"
  7. "fmt"
  8. "tailscale.com/types/tkatype"
  9. )
  10. // KeyKind describes the different varieties of a Key.
  11. type KeyKind uint8
  12. // Valid KeyKind values.
  13. const (
  14. KeyInvalid KeyKind = iota
  15. Key25519
  16. )
  17. func (k KeyKind) String() string {
  18. switch k {
  19. case KeyInvalid:
  20. return "invalid"
  21. case Key25519:
  22. return "25519"
  23. default:
  24. return fmt.Sprintf("Key?<%d>", int(k))
  25. }
  26. }
  27. // Key describes the public components of a key known to network-lock.
  28. type Key struct {
  29. Kind KeyKind `cbor:"1,keyasint"`
  30. // Votes describes the weight applied to signatures using this key.
  31. // Weighting is used to deterministically resolve branches in the AUM
  32. // chain (i.e. forks, where two AUMs exist with the same parent).
  33. Votes uint `cbor:"2,keyasint"`
  34. // Public encodes the public key of the key. For 25519 keys,
  35. // this is simply the point on the curve representing the public
  36. // key.
  37. Public []byte `cbor:"3,keyasint"`
  38. // Meta describes arbitrary metadata about the key. This could be
  39. // used to store the name of the key, for instance.
  40. Meta map[string]string `cbor:"12,keyasint,omitempty"`
  41. }
  42. // Clone makes an independent copy of Key.
  43. //
  44. // NOTE: There is a difference between a nil slice and an empty slice for encoding purposes,
  45. // so an implementation of Clone() must take care to preserve this.
  46. func (k Key) Clone() Key {
  47. out := k
  48. if k.Public != nil {
  49. out.Public = make([]byte, len(k.Public))
  50. copy(out.Public, k.Public)
  51. }
  52. if k.Meta != nil {
  53. out.Meta = make(map[string]string, len(k.Meta))
  54. for k, v := range k.Meta {
  55. out.Meta[k] = v
  56. }
  57. }
  58. return out
  59. }
  60. // MustID returns the KeyID of the key, panicking if an error is
  61. // encountered. This must only be used for tests.
  62. func (k Key) MustID() tkatype.KeyID {
  63. id, err := k.ID()
  64. if err != nil {
  65. panic(err)
  66. }
  67. return id
  68. }
  69. // ID returns the KeyID of the key.
  70. func (k Key) ID() (tkatype.KeyID, error) {
  71. switch k.Kind {
  72. // Because 25519 public keys are so short, we just use the 32-byte
  73. // public as their 'key ID'.
  74. case Key25519:
  75. return tkatype.KeyID(k.Public), nil
  76. default:
  77. return nil, fmt.Errorf("unknown key kind: %v", k.Kind)
  78. }
  79. }
  80. // Ed25519 returns the ed25519 public key encoded by Key. An error is
  81. // returned for keys which do not represent ed25519 public keys.
  82. func (k Key) Ed25519() (ed25519.PublicKey, error) {
  83. switch k.Kind {
  84. case Key25519:
  85. return ed25519.PublicKey(k.Public), nil
  86. default:
  87. return nil, fmt.Errorf("key is of type %v, not ed25519", k.Kind)
  88. }
  89. }
  90. const maxMetaBytes = 512
  91. func (k Key) StaticValidate() error {
  92. if k.Votes > 4096 {
  93. return fmt.Errorf("excessive key weight: %d > 4096", k.Votes)
  94. }
  95. if k.Votes == 0 {
  96. return errors.New("key votes must be non-zero")
  97. }
  98. // We have an arbitrary upper limit on the amount
  99. // of metadata that can be associated with a key, so
  100. // people don't start using it as a key-value store and
  101. // causing pathological cases due to the number + size of
  102. // AUMs.
  103. var metaBytes uint
  104. for k, v := range k.Meta {
  105. metaBytes += uint(len(k) + len(v))
  106. }
  107. if metaBytes > maxMetaBytes {
  108. return fmt.Errorf("key metadata too big (%d > %d)", metaBytes, maxMetaBytes)
  109. }
  110. switch k.Kind {
  111. case Key25519:
  112. default:
  113. return fmt.Errorf("unrecognized key kind: %v", k.Kind)
  114. }
  115. return nil
  116. }