diff options
Diffstat (limited to 'net')
| -rw-r--r-- | net/currenttime/currenttime.go | 42 | ||||
| -rw-r--r-- | net/currenttime/currenttime_test.go | 14 | ||||
| -rw-r--r-- | net/currenttime/mintime.txt | 1 | ||||
| -rw-r--r-- | net/currenttime/update-current-time.go | 20 | ||||
| -rw-r--r-- | net/tlsdial/tlsdial.go | 2 |
5 files changed, 79 insertions, 0 deletions
diff --git a/net/currenttime/currenttime.go b/net/currenttime/currenttime.go new file mode 100644 index 000000000..7ef2a1c56 --- /dev/null +++ b/net/currenttime/currenttime.go @@ -0,0 +1,42 @@ +// Copyright (c) Tailscale Inc & AUTHORS +// SPDX-License-Identifier: BSD-3-Clause + +// Package currenttime provides a fallback "current time" that can be used as +// the minimum possible time for things like TLS certificate verification. +// +// This ensures that if a Tailscale client's clock is wrong, it can still +// verify TLS certificates, assuming that the server certificate hasn't already +// expired from the point of view of the minimum time. +// +// In the future, we may want to consider caching the last known current time +// on-disk to improve the accuracy of this fallback. +package currenttime + +import ( + _ "embed" + "strconv" + "time" +) + +//go:embed mintime.txt +var minTimeUnixMs string + +var minCurrentTime time.Time + +func init() { + ms, err := strconv.ParseInt(minTimeUnixMs, 10, 64) + if err != nil { + panic(err) + } + minCurrentTime = time.UnixMilli(int64(ms)) +} + +// Now returns the current time as per [time.Now], except that if it is before +// the baked-in "minimum current time", that value will be returned instead. +func Now() time.Time { + now := time.Now() + if now.Before(minCurrentTime) { + return minCurrentTime + } + return now +} diff --git a/net/currenttime/currenttime_test.go b/net/currenttime/currenttime_test.go new file mode 100644 index 000000000..958a8436e --- /dev/null +++ b/net/currenttime/currenttime_test.go @@ -0,0 +1,14 @@ +package currenttime + +import ( + "testing" + "time" +) + +func TestMinTime(t *testing.T) { + // The baked-in time should always be before the current time. + now := time.Now() + if !minCurrentTime.Before(now) { + t.Fatalf("minCurrentTime is not before the current time: %v >= %v", minCurrentTime, now) + } +} diff --git a/net/currenttime/mintime.txt b/net/currenttime/mintime.txt new file mode 100644 index 000000000..5da66af78 --- /dev/null +++ b/net/currenttime/mintime.txt @@ -0,0 +1 @@ +1741638824797
\ No newline at end of file diff --git a/net/currenttime/update-current-time.go b/net/currenttime/update-current-time.go new file mode 100644 index 000000000..717a984ce --- /dev/null +++ b/net/currenttime/update-current-time.go @@ -0,0 +1,20 @@ +// Copyright (c) Tailscale Inc & AUTHORS +// SPDX-License-Identifier: BSD-3-Clause + +//go:build ignore + +package main + +import ( + "fmt" + "log" + "os" + "time" +) + +func main() { + contents := fmt.Sprintf(`%d`, time.Now().UnixMilli()) + if err := os.WriteFile("mintime.txt", []byte(contents), 0644); err != nil { + log.Fatal(err) + } +} diff --git a/net/tlsdial/tlsdial.go b/net/tlsdial/tlsdial.go index 4d22383ef..832a3e67a 100644 --- a/net/tlsdial/tlsdial.go +++ b/net/tlsdial/tlsdial.go @@ -29,6 +29,7 @@ import ( "tailscale.com/health" "tailscale.com/hostinfo" "tailscale.com/net/bakedroots" + "tailscale.com/net/currenttime" "tailscale.com/net/tlsdial/blockblame" ) @@ -144,6 +145,7 @@ func Config(host string, ht *health.Tracker, base *tls.Config) *tls.Config { opts := x509.VerifyOptions{ DNSName: cs.ServerName, Intermediates: x509.NewCertPool(), + CurrentTime: currenttime.Now(), // helps if the system clock is wrong } for _, cert := range cs.PeerCertificates[1:] { opts.Intermediates.AddCert(cert) |
