|
|
|
|
@ -7,6 +7,8 @@ import ( |
|
|
|
|
"bufio" |
|
|
|
|
"bytes" |
|
|
|
|
"context" |
|
|
|
|
"crypto/ed25519" |
|
|
|
|
"encoding/base64" |
|
|
|
|
"encoding/binary" |
|
|
|
|
"encoding/json" |
|
|
|
|
"errors" |
|
|
|
|
@ -424,7 +426,7 @@ func (c *Direct) doLogin(ctx context.Context, opt loginOpt) (mustRegen bool, new |
|
|
|
|
tryingNewKey := c.tryingNewKey |
|
|
|
|
serverKey := c.serverKey |
|
|
|
|
serverNoiseKey := c.serverNoiseKey |
|
|
|
|
authKey := c.authKey |
|
|
|
|
authKey, isWrapped, wrappedSig, wrappedKey := decodeWrappedAuthkey(c.authKey, c.logf) |
|
|
|
|
hi := c.hostInfoLocked() |
|
|
|
|
backendLogID := hi.BackendLogID |
|
|
|
|
expired := c.expiry != nil && !c.expiry.IsZero() && c.expiry.Before(c.timeNow()) |
|
|
|
|
@ -510,6 +512,22 @@ func (c *Direct) doLogin(ctx context.Context, opt loginOpt) (mustRegen bool, new |
|
|
|
|
if nodeKeySignature, err = resignNKS(persist.NetworkLockKey, tryingNewKey.Public(), opt.OldNodeKeySignature); err != nil { |
|
|
|
|
c.logf("Failed re-signing node-key signature: %v", err) |
|
|
|
|
} |
|
|
|
|
} else if isWrapped { |
|
|
|
|
// We were given a wrapped pre-auth key, which means that in addition
|
|
|
|
|
// to being a regular pre-auth key there was a suffix with information to
|
|
|
|
|
// generate a tailnet-lock signature.
|
|
|
|
|
nk, err := tryingNewKey.Public().MarshalBinary() |
|
|
|
|
if err != nil { |
|
|
|
|
return false, "", nil, fmt.Errorf("marshalling node-key: %w", err) |
|
|
|
|
} |
|
|
|
|
sig := &tka.NodeKeySignature{ |
|
|
|
|
SigKind: tka.SigRotation, |
|
|
|
|
Pubkey: nk, |
|
|
|
|
Nested: wrappedSig, |
|
|
|
|
} |
|
|
|
|
sigHash := sig.SigHash() |
|
|
|
|
sig.Signature = ed25519.Sign(wrappedKey, sigHash[:]) |
|
|
|
|
nodeKeySignature = sig.Serialize() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if backendLogID == "" { |
|
|
|
|
@ -1713,6 +1731,43 @@ func (c *Direct) ReportHealthChange(sys health.Subsystem, sysErr error) { |
|
|
|
|
res.Body.Close() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// decodeWrappedAuthkey separates wrapping information from an authkey, if any.
|
|
|
|
|
// In all cases the authkey is returned, sans wrapping information if any.
|
|
|
|
|
//
|
|
|
|
|
// If the authkey is wrapped, isWrapped returns true, along with the wrapping signature
|
|
|
|
|
// and private key.
|
|
|
|
|
func decodeWrappedAuthkey(key string, logf logger.Logf) (authKey string, isWrapped bool, sig *tka.NodeKeySignature, priv ed25519.PrivateKey) { |
|
|
|
|
authKey, suffix, found := strings.Cut(key, "--TL") |
|
|
|
|
if !found { |
|
|
|
|
return key, false, nil, nil |
|
|
|
|
} |
|
|
|
|
sigBytes, privBytes, found := strings.Cut(suffix, "-") |
|
|
|
|
if !found { |
|
|
|
|
logf("decoding wrapped auth-key: did not find delimiter") |
|
|
|
|
return key, false, nil, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
rawSig, err := base64.RawStdEncoding.DecodeString(sigBytes) |
|
|
|
|
if err != nil { |
|
|
|
|
logf("decoding wrapped auth-key: signature decode: %v", err) |
|
|
|
|
return key, false, nil, nil |
|
|
|
|
} |
|
|
|
|
rawPriv, err := base64.RawStdEncoding.DecodeString(privBytes) |
|
|
|
|
if err != nil { |
|
|
|
|
logf("decoding wrapped auth-key: priv decode: %v", err) |
|
|
|
|
return key, false, nil, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sig = new(tka.NodeKeySignature) |
|
|
|
|
if err := sig.Unserialize([]byte(rawSig)); err != nil { |
|
|
|
|
logf("decoding wrapped auth-key: signature: %v", err) |
|
|
|
|
return key, false, nil, nil |
|
|
|
|
} |
|
|
|
|
priv = ed25519.PrivateKey(rawPriv) |
|
|
|
|
|
|
|
|
|
return authKey, true, sig, priv |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
|
metricMapRequestsActive = clientmetric.NewGauge("controlclient_map_requests_active") |
|
|
|
|
|
|
|
|
|
|