-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Expand file tree
/
Copy pathnl.go
More file actions
178 lines (150 loc) · 5.26 KB
/
nl.go
File metadata and controls
178 lines (150 loc) · 5.26 KB
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
// Copyright (c) Tailscale Inc & contributors
// SPDX-License-Identifier: BSD-3-Clause
package key
import (
"crypto/ed25519"
"crypto/subtle"
"go4.org/mem"
"tailscale.com/types/structs"
"tailscale.com/types/tkatype"
)
const (
// nlPrivateHexPrefix is the prefix used to identify a
// hex-encoded tailnet-lock key.
nlPrivateHexPrefix = "nlpriv:"
// nlPublicHexPrefix is the prefix used to identify the public
// side of a hex-encoded tailnet-lock key.
nlPublicHexPrefix = "nlpub:"
// nlPublicHexPrefixCLI is the prefix used for tailnet-lock keys
// when shown on the CLI.
// It's not practical for us to change the prefix everywhere due to
// compatibility with existing clients, but we can support both prefixes
// as well as use the CLI form when presenting to the user.
nlPublicHexPrefixCLI = "tlpub:"
)
// NLPrivate is a node-managed network-lock key, used for signing
// node-key signatures and authority update messages.
type NLPrivate struct {
_ structs.Incomparable // because == isn't constant-time
k [ed25519.PrivateKeySize]byte
}
// IsZero reports whether k is the zero value.
func (k NLPrivate) IsZero() bool {
empty := NLPrivate{}
return subtle.ConstantTimeCompare(k.k[:], empty.k[:]) == 1
}
// NewNLPrivate creates and returns a new network-lock key.
func NewNLPrivate() NLPrivate {
// ed25519.GenerateKey 'clamps' the key, not that it
// matters given we don't do Diffie-Hellman.
_, priv, err := ed25519.GenerateKey(nil) // nil == crypto/rand
if err != nil {
panic(err)
}
var out NLPrivate
copy(out.k[:], priv)
return out
}
// MarshalText implements encoding.TextUnmarshaler.
func (k *NLPrivate) UnmarshalText(b []byte) error {
return parseHex(k.k[:], mem.B(b), mem.S(nlPrivateHexPrefix))
}
// AppendText implements encoding.TextAppender.
func (k NLPrivate) AppendText(b []byte) ([]byte, error) {
return appendHexKey(b, nlPrivateHexPrefix, k.k[:]), nil
}
// MarshalText implements encoding.TextMarshaler.
func (k NLPrivate) MarshalText() ([]byte, error) {
return k.AppendText(nil)
}
// Equal reports whether k and other are the same key.
func (k NLPrivate) Equal(other NLPrivate) bool {
return subtle.ConstantTimeCompare(k.k[:], other.k[:]) == 1
}
// Public returns the public component of this key.
func (k NLPrivate) Public() NLPublic {
var out NLPublic
copy(out.k[:], ed25519.PrivateKey(k.k[:]).Public().(ed25519.PublicKey))
return out
}
// KeyID returns an identifier for this key.
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.Signer.
func (k NLPrivate) SignAUM(sigHash tkatype.AUMSigHash) ([]tkatype.Signature, error) {
return []tkatype.Signature{{
KeyID: k.KeyID(),
Signature: ed25519.Sign(ed25519.PrivateKey(k.k[:]), sigHash[:]),
}}, nil
}
// SignNKS signs the tka.NodeKeySignature identified by sigHash.
func (k NLPrivate) SignNKS(sigHash tkatype.NKSSigHash) ([]byte, error) {
return ed25519.Sign(ed25519.PrivateKey(k.k[:]), sigHash[:]), nil
}
// NLPublic is the public portion of a a NLPrivate.
type NLPublic struct {
k [ed25519.PublicKeySize]byte
}
// NLPublicFromEd25519Unsafe converts an ed25519 public key into
// a type of NLPublic.
//
// New uses of this function should be avoided, as it's possible to
// accidentally construct an NLPublic from a non network-lock key.
func NLPublicFromEd25519Unsafe(public ed25519.PublicKey) NLPublic {
var out NLPublic
copy(out.k[:], public)
return out
}
// UnmarshalText implements encoding.TextUnmarshaler. This function
// is able to decode both the CLI form (tlpub:<hex>) & the
// regular form (nlpub:<hex>).
func (k *NLPublic) UnmarshalText(b []byte) error {
if mem.HasPrefix(mem.B(b), mem.S(nlPublicHexPrefix)) {
return parseHex(k.k[:], mem.B(b), mem.S(nlPublicHexPrefix))
}
return parseHex(k.k[:], mem.B(b), mem.S(nlPublicHexPrefixCLI))
}
// AppendText implements encoding.TextAppender.
func (k NLPublic) AppendText(b []byte) ([]byte, error) {
return appendHexKey(b, nlPublicHexPrefix, k.k[:]), nil
}
// MarshalText implements encoding.TextMarshaler, emitting a
// representation of the form nlpub:<hex>.
func (k NLPublic) MarshalText() ([]byte, error) {
return k.AppendText(nil)
}
// CLIString returns a marshalled representation suitable for use
// with tailnet lock commands, of the form tlpub:<hex> instead of
// the nlpub:<hex> form emitted by MarshalText. Both forms can
// be decoded by UnmarshalText.
func (k NLPublic) CLIString() string {
return string(appendHexKey(nil, nlPublicHexPrefixCLI, k.k[:]))
}
// Verifier returns a ed25519.PublicKey that can be used to
// verify signatures.
func (k NLPublic) Verifier() ed25519.PublicKey {
return ed25519.PublicKey(k.k[:])
}
// IsZero reports whether k is the zero value.
func (k NLPublic) IsZero() bool {
return k.Equal(NLPublic{})
}
// Equal reports whether k and other are the same key.
func (k NLPublic) Equal(other NLPublic) bool {
return subtle.ConstantTimeCompare(k.k[:], other.k[:]) == 1
}
// KeyID returns a tkatype.KeyID that can be used with a tka.Authority.
func (k NLPublic) KeyID() tkatype.KeyID {
return k.k[:]
}