summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/update-current-time.yml44
-rw-r--r--cmd/derper/depaware.txt1
-rw-r--r--cmd/k8s-operator/depaware.txt1
-rw-r--r--cmd/tailscale/depaware.txt1
-rw-r--r--cmd/tailscaled/depaware.txt1
-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
10 files changed, 127 insertions, 0 deletions
diff --git a/.github/workflows/update-current-time.yml b/.github/workflows/update-current-time.yml
new file mode 100644
index 000000000..f1c86c0be
--- /dev/null
+++ b/.github/workflows/update-current-time.yml
@@ -0,0 +1,44 @@
+name: update-current-time
+
+on:
+ # allow manual execution
+ workflow_dispatch:
+
+ # run every 14 days
+ schedule:
+ - cron: "0 0 */14 * *"
+
+concurrency:
+ group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
+ cancel-in-progress: true
+
+jobs:
+ update-flake:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Check out code
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+
+ - name: Get access token
+ uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a # v2.1.0
+ id: generate-token
+ with:
+ app_id: ${{ secrets.LICENSING_APP_ID }}
+ installation_retrieval_mode: "id"
+ installation_retrieval_payload: ${{ secrets.LICENSING_APP_INSTALLATION_ID }}
+ private_key: ${{ secrets.LICENSING_APP_PRIVATE_KEY }}
+
+ - name: Send pull request
+ uses: peter-evans/create-pull-request@dd2324fc52d5d43c699a5636bcf19fceaa70c284 #v7.0.7
+ with:
+ token: ${{ steps.generate-token.outputs.token }}
+ author: Time Updater <noreply+time-updater@tailscale.com>
+ committer: Time Updater <noreply+time-updater@tailscale.com>
+ branch: time-updates
+ commit-message: "net/currentime: update minimum time"
+ title: "net/currentime: update minimum time"
+ body: Triggered by ${{ github.repository }}@${{ github.sha }}
+ signoff: true
+ delete-branch: true
+ reviewers: andrew-d
diff --git a/cmd/derper/depaware.txt b/cmd/derper/depaware.txt
index 1812a1a8d..d6ce74d72 100644
--- a/cmd/derper/depaware.txt
+++ b/cmd/derper/depaware.txt
@@ -103,6 +103,7 @@ tailscale.com/cmd/derper dependencies: (generated by github.com/tailscale/depawa
tailscale.com/kube/kubetypes from tailscale.com/envknob
tailscale.com/metrics from tailscale.com/cmd/derper+
tailscale.com/net/bakedroots from tailscale.com/net/tlsdial
+ tailscale.com/net/currenttime from tailscale.com/net/tlsdial
tailscale.com/net/dnscache from tailscale.com/derp/derphttp
tailscale.com/net/ktimeout from tailscale.com/cmd/derper
tailscale.com/net/netaddr from tailscale.com/ipn+
diff --git a/cmd/k8s-operator/depaware.txt b/cmd/k8s-operator/depaware.txt
index 54d9bd248..c3bbf043b 100644
--- a/cmd/k8s-operator/depaware.txt
+++ b/cmd/k8s-operator/depaware.txt
@@ -847,6 +847,7 @@ tailscale.com/cmd/k8s-operator dependencies: (generated by github.com/tailscale/
tailscale.com/net/bakedroots from tailscale.com/net/tlsdial+
tailscale.com/net/captivedetection from tailscale.com/ipn/ipnlocal+
tailscale.com/net/connstats from tailscale.com/net/tstun+
+ tailscale.com/net/currenttime from tailscale.com/net/tlsdial
tailscale.com/net/dns from tailscale.com/ipn/ipnlocal+
tailscale.com/net/dns/publicdns from tailscale.com/net/dns+
tailscale.com/net/dns/recursive from tailscale.com/net/dnsfallback
diff --git a/cmd/tailscale/depaware.txt b/cmd/tailscale/depaware.txt
index afe62165c..7814ea677 100644
--- a/cmd/tailscale/depaware.txt
+++ b/cmd/tailscale/depaware.txt
@@ -102,6 +102,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
tailscale.com/metrics from tailscale.com/derp+
tailscale.com/net/bakedroots from tailscale.com/net/tlsdial
tailscale.com/net/captivedetection from tailscale.com/net/netcheck
+ tailscale.com/net/currenttime from tailscale.com/net/tlsdial
tailscale.com/net/dns/recursive from tailscale.com/net/dnsfallback
tailscale.com/net/dnscache from tailscale.com/control/controlhttp+
tailscale.com/net/dnsfallback from tailscale.com/control/controlhttp+
diff --git a/cmd/tailscaled/depaware.txt b/cmd/tailscaled/depaware.txt
index c0f592ea1..2e82b398c 100644
--- a/cmd/tailscaled/depaware.txt
+++ b/cmd/tailscaled/depaware.txt
@@ -297,6 +297,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
tailscale.com/net/bakedroots from tailscale.com/net/tlsdial+
tailscale.com/net/captivedetection from tailscale.com/ipn/ipnlocal+
tailscale.com/net/connstats from tailscale.com/net/tstun+
+ tailscale.com/net/currenttime from tailscale.com/net/tlsdial
tailscale.com/net/dns from tailscale.com/cmd/tailscaled+
tailscale.com/net/dns/publicdns from tailscale.com/net/dns+
tailscale.com/net/dns/recursive from tailscale.com/net/dnsfallback
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)