summaryrefslogtreecommitdiffhomepage
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/currenttime/currenttime.go42
-rw-r--r--net/currenttime/currenttime_test.go14
-rw-r--r--net/currenttime/mintime.txt1
-rw-r--r--net/currenttime/update-current-time.go20
-rw-r--r--net/tlsdial/tlsdial.go2
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)