tailscale/wgengine/magicsock/disco_atomic_test.go
James Tucker c09c95ef67 types/key,wgengine/magicsock,control/controlclient,ipn: add debug disco key rotation
Adds the ability to rotate discovery keys on running clients, needed for
testing upcoming disco key distribution changes.

Introduces key.DiscoKey, an atomic container for a disco private key,
public key, and the public key's ShortString, replacing the prior
separate atomic fields.

magicsock.Conn has a new RotateDiscoKey method, and access to this is
provided via localapi and a CLI debug command.

Note that this implementation is primarily for testing as it stands, and
regular use should likely introduce an additional mechanism that allows
the old key to be used for some time, to provide a seamless key rotation
rather than one that invalidates all sessions.

Updates tailscale/corp#34037

Signed-off-by: James Tucker <james@tailscale.com>
2025-11-18 12:16:15 -08:00

71 lines
1.6 KiB
Go

// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
package magicsock
import (
"testing"
"tailscale.com/types/key"
)
func TestDiscoAtomic(t *testing.T) {
var dk discoAtomic
dk.Set(key.NewDisco())
private := dk.Private()
public := dk.Public()
short := dk.Short()
if private.IsZero() {
t.Fatal("DiscoKey private key should not be zero")
}
if public.IsZero() {
t.Fatal("DiscoKey public key should not be zero")
}
if short == "" {
t.Fatal("DiscoKey short string should not be empty")
}
if public != private.Public() {
t.Fatal("DiscoKey public key doesn't match private key")
}
if short != public.ShortString() {
t.Fatal("DiscoKey short string doesn't match public key")
}
gotPrivate, gotPublic := dk.Pair()
if !gotPrivate.Equal(private) {
t.Fatal("Pair() returned different private key")
}
if gotPublic != public {
t.Fatal("Pair() returned different public key")
}
}
func TestDiscoAtomicSet(t *testing.T) {
var dk discoAtomic
dk.Set(key.NewDisco())
oldPrivate := dk.Private()
oldPublic := dk.Public()
newPrivate := key.NewDisco()
dk.Set(newPrivate)
currentPrivate := dk.Private()
currentPublic := dk.Public()
if currentPrivate.Equal(oldPrivate) {
t.Fatal("DiscoKey private key should have changed after Set")
}
if currentPublic == oldPublic {
t.Fatal("DiscoKey public key should have changed after Set")
}
if !currentPrivate.Equal(newPrivate) {
t.Fatal("DiscoKey private key doesn't match the set key")
}
if currentPublic != newPrivate.Public() {
t.Fatal("DiscoKey public key doesn't match derived from set private key")
}
}