-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathroughntstime.go
117 lines (98 loc) · 2.65 KB
/
roughntstime.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) Matter Labs
//
// Gets the rough network time using NTS-KE.
// It queries a number of servers and returns the time from the last server that responds.
// It returns an error if it fails to query enough servers or if the time fluctuates too much.
package vault_auth_tee
import (
"crypto/tls"
"errors"
"log"
"math/rand"
"time"
"gitlab.com/hacklunch/ntp"
"gitlab.com/hacklunch/ntske"
)
// Gets the rough network time using NTS-KE.
// It queries a number of servers and returns the time from the last server that responds.
// It returns an error if it fails to query enough servers or if the time fluctuates too much.
func getRoughNtsUnixTime() (time.Time, error) {
tlsconfig := &tls.Config{}
servers := []string{
"time.cloudflare.com",
"nts.ntp.se",
"gps.ntp.br",
"paris.time.system76.com",
"ntp3.fau.de",
"ptbtime1.ptb.de",
"ntppool1.time.nl",
"nts.netnod.se",
"time.txryan.com",
"ntpmon.dcs1.biz",
}
// Shuffle the servers to avoid always querying the same servers.
for i := range servers {
j := rand.Intn(i + 1)
servers[i], servers[j] = servers[j], servers[i]
}
numToQuery := 3
queried := 0
sumOffset := time.Duration(0)
retTime := time.Unix(0, 0)
for _, server := range servers {
ke, err := ntske.Connect(server, tlsconfig, false)
if err != nil {
log.Printf("Failed to connect to %v: %v\n", server, err)
continue
}
err = ke.Exchange()
if err != nil {
log.Printf("Key exchange failed for %v: %v\n", server, err)
continue
}
if len(ke.Meta.Cookie) == 0 {
log.Printf("No Cookies from %v: %v\n", server, err)
continue
}
if ke.Meta.Algo != ntske.AES_SIV_CMAC_256 {
log.Printf("Algorithm mismatch for %v: %v\n", server, err)
continue
}
err = ke.ExportKeys()
if err != nil {
log.Printf("Failed to export keys from %v: %v\n", server, err)
continue
}
var opt ntp.QueryOptions
opt.Port = int(ke.Meta.Port)
opt.NTS = true
opt.C2s = ke.Meta.C2sKey
opt.S2c = ke.Meta.S2cKey
opt.Cookie = ke.Meta.Cookie[0]
opt.Debug = false
resp, err := ntp.QueryWithOptions(ke.Meta.Server, opt)
if err != nil {
log.Printf("Failed query NTP for %v: %v\n", server, err)
continue
}
err = resp.Validate()
if err != nil {
log.Printf("Failed to validate NTP response for %v: %v\n", server, err)
continue
}
sumOffset += resp.ClockOffset.Abs()
queried++
if queried >= numToQuery {
retTime = resp.Time
break
}
}
if queried < numToQuery {
return retTime, errors.New("failed to query enough servers")
}
if sumOffset > time.Minute {
return retTime, errors.New("queried time fluctuates too much")
}
return retTime, nil
}