ntpstats.nts¶
Network Time Security (RFC 8915) measurement client.
Optional: needs pip install 'ntpstats[nts]' (pyOpenSSL for the TLS 1.3
keying-material exporter, which Python's ssl module does not expose, and
cryptography for AEAD_AES_SIV_CMAC_256). The rest of ntpstats keeps
working without these.
Flow::
session = NTSSession("time.cloudflare.com") # NTS-KE over TLS 1.3, ALPN "ntske/1"
r = session.query() # authenticated NTPv4 exchange
r.offset, r.delay, session.cookies_left
- NTS-KE (RFC 8915 section 4): negotiates NTPv4 (protocol 0) and AEAD 15
(AES-SIV-CMAC-256), receives cookies and an optional NTP server/port, and
derives the C2S/S2C keys with the exporter label
EXPORTER-network-time-security. - NTP (section 5): Unique Identifier, NTS Cookie, Cookie Placeholder and
NTS Authenticator extension fields. The response is authenticated, its
Unique Identifier checked, and the encrypted new cookies stored (cookies
are single use). An NTS NAK (Kiss-o'-Death
NTSN) triggers a new key exchange on the next query.
Certificates are verified against the system trust store (or cafile),
including the host name, unless verify=False (only for lab testing).
NTSSession
¶
Keeps keys and cookies; performs a new key exchange when needed.
key_exchange(host, port=4460, timeout=5.0, verify=True, cafile=None, family=0, deny=())
¶
NTS-KE (RFC 8915). deny lists NTP server names already in use, sent
as NTP Server Deny records so that an NTS pool returns a different one.
build_request(keys, placeholders=0)
¶
Return (packet, transmit_nonce, unique_id).
verify_response(keys, data, uid)
¶
Authenticate a server response; return the new cookies it carries.
pool_sessions(pool, n=3, **kw)
¶
Up to n sessions with different NTP servers from an NTS pool.
Each key exchange sends NTP Server Deny records (draft-ietf-ntp-nts- keyexchange-pool) for the servers already obtained. A pool that ignores them may return duplicates, which are dropped.