7 releases (3 stable)
| new 1.1.1 | May 13, 2026 |
|---|---|
| 1.1.0 | May 12, 2026 |
| 1.0.0 | Apr 28, 2026 |
| 0.4.0 | Jan 23, 2026 |
| 0.1.0 | Nov 5, 2025 |
#1503 in Network programming
2,096 downloads per month
Used in rkik
125KB
2.5K
SLoC
rkik-nts
A high-level NTS (Network Time Security) client library for Rust with a self-contained RFC 8915 implementation.
This library provides a simple, safe, and ergonomic API for querying time from NTS-secured NTP servers. It handles the complexity of NTS key exchange and authenticated time synchronization, making it easy to integrate secure time synchronization into your applications.
Features
- Secure: Full NTS (Network Time Security) support for authenticated time queries
- Certificate Diagnostics: TLS certificate information capture for security auditing and diagnostics
- TLS Debugging: optional
tls-keylogfeature for Wireshark traffic analysis - Simple API: Easy-to-use client interface with sensible defaults
- Async: Built on Tokio for efficient async I/O
- Configurable: Flexible configuration options for advanced use cases
- Self-contained: NTS-KE and NTS-protected NTP are implemented directly in this crate
Quick Start
Add to your Cargo.toml:
[dependencies]
rkik-nts = "1"
tokio = { version = "1", features = ["full"] }
Basic usage:
use rkik_nts::{NtsClient, NtsClientConfig};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a client configuration
let config = NtsClientConfig::new("time.cloudflare.com");
// Create and connect the client
let mut client = NtsClient::new(config);
client.connect().await?;
// Query the current time
let time = client.get_time().await?;
println!("Network time: {:?}", time.network_time);
println!("Offset (ms): {} ms", time.offset_signed());
println!("Authenticated: {}", time.authenticated);
Ok(())
}
Examples
Simple Client
cargo run --example simple_client --features tracing-subscriber
End-to-End NTS Validation
cargo run --example nts_end_to_end --features tracing-subscriber
Certificate Information
Access TLS certificate information from the NTS-KE handshake:
use rkik_nts::{NtsClient, NtsClientConfig};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = NtsClientConfig::new("time.cloudflare.com");
let mut client = NtsClient::new(config);
client.connect().await?;
// Access certificate information
if let Some(ke_result) = client.nts_ke_info() {
if let Some(cert) = &ke_result.certificate {
println!("Certificate Subject: {}", cert.subject);
println!("Certificate Issuer: {}", cert.issuer);
println!("Valid from: {} to {}", cert.valid_from, cert.valid_until);
println!("SHA-256 Fingerprint: {}", cert.fingerprint_sha256);
println!("Self-signed: {}", cert.is_self_signed);
}
}
Ok(())
}
Run the certificate example:
cargo run --example test_certificate --features tracing-subscriber
Custom Configuration
use rkik_nts::{NtsClient, NtsClientConfig};
use std::time::Duration;
let config = NtsClientConfig::new("time.cloudflare.com")
.with_port(4460)
.with_timeout(Duration::from_secs(5))
.with_max_retries(3);
let mut client = NtsClient::new(config);
client.connect().await?;
let time = client.get_time().await?;
max_retries controls how many additional authenticated query attempts are made
after transport or packet-validation failures before get_time() returns an error.
See the examples/ directory for more detailed examples.
Advanced Features
TLS Traffic Analysis with SSLKEYLOGFILE
For debugging and network analysis, you can capture TLS session keys for Wireshark decryption.
This is disabled by default and requires the tls-keylog feature:
# Set environment variable to enable keylog
export SSLKEYLOGFILE=/tmp/sslkeylog.txt
# Run your application or example
cargo run --example test_certificate --features "tracing-subscriber tls-keylog"
# Use the keylog file in Wireshark:
# Edit → Preferences → Protocols → TLS → (Pre)-Master-Secret log filename
Do not enable this in production. The exported TLS secrets also expose the derived NTS keys for that session.
Public NTS Servers
Here are some public NTS servers you can use for testing:
time.cloudflare.com- Cloudflarents.ntp.se- Netnod (Sweden)ntppool1.time.nl- NLnet Labs (Netherlands)time.txryan.com- Tanner Ryannts.ntp.org.au- Australian NTP Poolptbtime1.ptb.de- PTB (Germany, public service availability not guaranteed)
The current network test suite is validated against time.cloudflare.com and nts.ntp.se.
PTB servers are exercised opportunistically because PTB explicitly states that uninterrupted public availability is not guaranteed.
Integration with rkik
This library was initially designed for seamless integration with rkik, but is now mainly meant to be used as a standalone NTS client library. The API is intentionally kept simple and focused on authenticated time acquisition.
Architecture
The library is structured into several modules:
client: High-level NTS client implementationconfig: Configuration types and builderserror: Error types and result aliasesnts_ke: NTS Key Exchange protocol implementationtypes: Common types (TimeSnapshot, NtsKeResult, etc.)
How NTS Works
Network Time Security (NTS) is a security extension for NTP that provides:
- Authentication: Cryptographic verification that time data comes from the expected server
- Encryption: Protection of time synchronization traffic
- Resistance to replay attacks: Each query uses unique authentication cookies
The protocol works in two phases:
- NTS-KE (Key Exchange): TLS connection to exchange keys and cookies
- NTP with NTS: UDP-based time queries using the negotiated keys
This library handles both phases transparently.
Requirements
- Rust 1.70 or later
- Tokio runtime
Development
# Build the library
cargo build
# Run tests
cargo test
# Run examples
cargo run --example simple_client --features tracing-subscriber
# Build documentation
cargo doc --open
See CONTRIBUTING.md for development guidelines.
Contributing
Contributions are welcome! Please see CONTRIBUTING.md for details.
Resources
Dependencies
~20–36MB
~501K SLoC