Skip to main content

rtime_nts/
lib.rs

1//! Network Time Security (NTS, [RFC 8915](https://www.rfc-editor.org/rfc/rfc8915)) for the
2//! [rTime](https://github.com/ZerosAndOnesLLC/rTime) NTP daemon.
3//!
4//! NTS adds authentication and replay protection to NTPv4 without per-packet asymmetric
5//! crypto: a TLS 1.3 handshake (NTS-KE) establishes keys and issues opaque cookies, and each
6//! subsequent NTP exchange is protected with AEAD (`AEAD_AES_SIV_CMAC_256`).
7//!
8//! # Modules
9//!
10//! - [`ke`] — the NTS-KE (key establishment) record exchange over TLS.
11//! - [`records`] — NTS-KE record framing and parsing.
12//! - [`aead`] — AEAD encryption/decryption of NTP extension fields.
13//! - [`cookie`] — cookie issuance, storage, and rotation.
14//!
15//! Protocol constants (algorithm ids, ports, key lengths) and the crate error type
16//! [`NtsError`] are defined at the crate root.
17
18pub mod aead;
19pub mod cookie;
20pub mod ke;
21pub mod records;
22
23/// AEAD_AES_SIV_CMAC_256 algorithm identifier (RFC 5116 Section 5.4).
24/// This is the mandatory-to-implement AEAD algorithm for NTS (RFC 8915 Section 5.1).
25pub const AEAD_AES_SIV_CMAC_256: u16 = 15;
26
27/// NTPv4 next protocol identifier for NTS-KE (RFC 8915 Section 4.1.2).
28pub const NTS_NEXT_PROTOCOL_NTPV4: u16 = 0;
29
30/// Key length in bytes for AEAD_AES_SIV_CMAC_256.
31/// The "256" refers to the output tag size; internally it uses two 128-bit subkeys (32 bytes total).
32pub const AEAD_AES_SIV_CMAC_256_KEYLEN: usize = 32;
33
34/// Default number of cookies provided during NTS-KE.
35pub const DEFAULT_COOKIE_COUNT: usize = 8;
36
37/// NTS-KE TCP port (RFC 8915 Section 4).
38pub const NTS_KE_PORT: u16 = 4460;
39
40/// TLS exporter label for NTS key derivation (RFC 8915 Section 5.1).
41pub const NTS_TLS_EXPORTER_LABEL: &str = "EXPORTER-network-time-security";
42
43#[derive(Debug, thiserror::Error)]
44pub enum NtsError {
45    #[error("record too short: need at least {expected} bytes, got {got}")]
46    RecordTooShort { expected: usize, got: usize },
47
48    #[error("unknown record type: {0}")]
49    UnknownRecordType(u16),
50
51    #[error("invalid record body length: declared {declared}, available {available}")]
52    InvalidBodyLength { declared: usize, available: usize },
53
54    #[error("NTS-KE error code: {0}")]
55    KeError(u16),
56
57    #[error("NTS-KE warning code: {0}")]
58    KeWarning(u16),
59
60    #[error("missing required record: {0}")]
61    MissingRecord(&'static str),
62
63    #[error("unsupported next protocol: {0}")]
64    UnsupportedProtocol(u16),
65
66    #[error("unsupported AEAD algorithm: {0}")]
67    UnsupportedAlgorithm(u16),
68
69    #[error("no cookies received from server")]
70    NoCookies,
71
72    #[error("AEAD encryption failed")]
73    EncryptionFailed,
74
75    #[error("AEAD decryption failed (authentication tag mismatch)")]
76    DecryptionFailed,
77
78    #[error("invalid cookie: {0}")]
79    InvalidCookie(String),
80
81    #[error("TLS error: {0}")]
82    Tls(String),
83
84    #[error("I/O error: {0}")]
85    Io(#[from] std::io::Error),
86
87    #[error("extension field too short: need at least {expected} bytes, got {got}")]
88    ExtensionTooShort { expected: usize, got: usize },
89
90    #[error("invalid extension field length: {0}")]
91    InvalidExtensionLength(u16),
92}