|
|
|
@ -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")
|
|
|
|
|
|
|
|
|
|