21 releases (stable)

1.2.0-draft5 Apr 2, 2022
1.1.8 Mar 21, 2020
1.1.7 Oct 12, 2019
1.1.5 May 11, 2019
0.1.1 Dec 30, 2017

#304 in Cryptography

Download history 8/week @ 2024-02-26 102/week @ 2024-04-01

102 downloads per month
Used in roughenough-fuzz

Apache-2.0

185KB
3.5K SLoC

Roughenough

crates.io Build Apache License 2

Roughenough is an RFC-draft compliant Roughtime secure time synchronization client and server implementation in Rust.

Roughenough's server and client are functionally complete and at feature parity with the reference C++ and Golang implementations.

Requires latest stable Rust to compile. Contributions welcome, see CONTRIBUTING for instructions and limitations for areas that could use attention.

RFC Work-In-Progress

Roughenough implements the Roughtime protocol as specified in the draft-5 RFC.

Important differences from the draft RFC

  1. Roughenough uses SHA-512/256 to compute the Merkle tree. Draft-5 of the RFC uses a bespoke 32-byte SHA-512 prefix without rationale or justification. Given that standardized 32-byte SHA-512/256 exists and is already implemented widely, I'm sticking with it while I advocate for the RFC to move away from the custom prefix and adopt SHA-512/256.
  2. The server and client send/expect RFC protocol version 1 (VER tag is 0x00000001) instead of the draft's suggested 0x80000000 + version.

The Roughenough server operates both the "classic" protocol and the RFC compliant protocol at the same time on a single serving port (the 8-byte magic frame value added by the RFC is used to distinguish classic vs. rfc requests).

The new -p/--protocol flag of roughenough-client controls the protocol version to use in requests (0 = classic protocol, 1 = RFC protocol). The default is 0 the "classic" protocol, until the RFC is finalized:

# send RFC protocol Roughtime requests
$ roughenough-client -p 1 roughtime.int08h.com 2002

Building and Running

Minimum Supported Rust Version (MSRV)

Roughenough uses 2018 edition features and requires Rust 1.31 or newer to build.

Building

# Build roughenough
$ cargo build --release

The client binary is target/release/roughenough-client. After building you can copy the binary and run on its own (no cargo needed) if you wish.

$ cp target/release/roughenough-client /usr/local/bin 

Using the Client to Query a Roughtime Server

$ target/release/roughenough-client -v roughtime.int08h.com 2002
Requesting time from: "roughtime.int08h.com":2002
Received time from server: midpoint="Oct 26 2018 23:20:44", radius=1000000, verified=No (merkle_index=0)
Oct 26 2018 23:20:44

Setting The System Time on Linux

You can use the date utility on Linux machines to set the system time to the time determined by the Roughenough client:

sudo date --utc --set "$(roughenough-client -z roughtime.int08h.com 2002)"

Setting The System Time on FreeBSD

You can use the date utility on FreeBSD machines to set the system time to the time determined by the Roughenough client:

sudo date -u "$(roughenough-client -z roughtime.int08h.com 2002 -f %Y%m%d%H%M.%S)"

Validating Server Responses

Use the -p flag with the client to validate the server's response with its public key.

# The public key of 'roughtime.int08h.com' is stored in a DNS TXT record 
$ host -t TXT roughtime.int08h.com
roughtime.int08h.com descriptive text "016e6e0284d24c37c6e4d7d8d5b4e1d3c1949ceaa545bf875616c9dce0c9bec1"

# Validate the server response using its public key
$ target/release/roughenough-client -v roughtime.int08h.com 2002 -p 016e6e0284d24c37c6e4d7d8d5b4e1d3c1949ceaa545bf875616c9dce0c9bec1
Requesting time from: "roughtime.int08h.com":2002
Received time from server: midpoint="Oct 26 2018 23:22:20", radius=1000000, verified=Yes (merkle_index=0)
Oct 26 2018 23:22:20

The verified=Yes in the output confirms that the server's response had a valid signature.

Server Configuration

There are two (mutually exclusive) ways to configure the Roughenough server:

  1. A YAML file, or
  2. Environment variables

The server accepts the following configuration parameters:

YAML Key Environment Variable Necessity Description
interface ROUGHENOUGH_INTERFACE Required IP address or interface name for listening to client requests
port ROUGHENOUGH_PORT Required UDP port to listen for requests
seed ROUGHENOUGH_SEED Required A 32-byte hexadecimal value used to generate the server's long-term key pair. This is a secret value and must be un-guessable, treat it with care. (If compiled with KMS support, length will vary; see Optional Features)
batch_size ROUGHENOUGH_BATCH_SIZE Optional The maximum number of requests to process in one batch. All nonces in a batch are used to build a Merkle tree, the root of which is signed. Default is 64 requests per batch.
status_interval ROUGHENOUGH_STATUS_INTERVAL Optional Number of seconds between each logged status update. Default is 600 seconds (10 minutes).
health_check_port ROUGHENOUGH_HEALTH_CHECK_PORT Optional If present, enable an HTTP health check responder on the provided port. Use with caution, see Optional Features.
kms_protection ROUGHENOUGH_KMS_PROTECTION Optional If compiled with KMS support, the ID of the KMS key used to protect the long-term identity. See Optional Features.
fault_percentage ROUGHENOUGH_FAULT_PERCENTAGE Optional Likelihood (as a percentage) that the server will intentionally return an invalid client response. An integer range from 0 (disabled, all responses valid) to 50 (50% of responses will be invalid). Default is 0 (disabled).

YAML Configuration

The table above lists the YAML keys available in the config file. An example:

interface: 127.0.0.1
port: 8686
seed: f61075c988feb9cb700a4a6a3291bfbc9cab11b9c9eca8c802468eb38a43d7d3

Provide the config file as the single command-line argument to the Roughenough server binary:

$ /path/to/roughenough-server /path/to/config.yaml

Environment Configuration

Roughenough can be configured via the ROUGHENOUGH_* environment variables listed in the table above. Start the server with a single ENV argument to have Roughenough configure itself from the environment. Example:

$ export ROUGHENOUGH_INTERFACE=127.0.0.1
$ export ROUGHENOUGH_PORT=8686
$ export ROUGHENOUGH_SEED=f61075c988feb9cb700a4a6a3291bfbc9cab11b9c9eca8c802468eb38a43d7d3
$ /path/to/roughenough-server ENV

Starting the Server

# Build roughenough
$ cargo build --release

# Via a config file
$ target/release/roughenough-server example.cfg
2018-07-25 00:05:09 INFO  [server] Roughenough server v1.0.5 starting
2018-07-25 00:05:09 INFO  [server] Long-term public key: d0756ee69ff5fe96cbcf9273208fec53124b1dd3a24d3910e07c7c54e2473012
2018-07-25 00:05:09 INFO  [server] Ephemeral public key: 25fd5dc31ceee241aed3e643534e95ed0609e9a20982a45ac0312a5f55e2cc66
2018-07-25 00:05:09 INFO  [server] Server listening on 127.0.0.1:8686

# Or using environment variables
$ export ROUGHENOUGH_INTERFACE=127.0.0.1
$ export ROUGHENOUGH_PORT=8686
$ export ROUGHENOUGH_SEED=f61075c988feb9cb700a4a6a3291bfbc9cab11b9c9eca8c802468eb38a43d7d3
$ target/release/roughenough-server ENV
2018-07-25 00:05:09 INFO  [server] Roughenough server v1.0.5 starting
2018-07-25 00:05:09 INFO  [server] Long-term public key: d0756ee69ff5fe96cbcf9273208fec53124b1dd3a24d3910e07c7c54e2473012
2018-07-25 00:05:09 INFO  [server] Ephemeral public key: 25fd5dc31ceee241aed3e643534e95ed0609e9a20982a45ac0312a5f55e2cc66
2018-07-25 00:05:09 INFO  [server] Server listening on 127.0.0.1:8686

The resulting binary is target/release/roughenough-server. After building you can copy the binary and run on its own (no cargo needed):

$ cp target/release/roughenough-server /usr/local/bin 

Stopping the Server

Use Ctrl-C or kill the process.

Optional Features

Roughenough has two opt-in (disabled by default) features that are enabled either A) via a config setting, or B) at compile-time.

See OPTIONAL-FEATURES.md for details and instructions how to enable and use.

Limitations

Roughtime features not implemented by the server:

  • On-line (while server is running) key rotation. The server must be restarted to generate a new delegated key.
  • The Roughenough server depends on the host's time source to comply with the smeared leap-second requirement of the Roughtime protocol. A Roughenough server sourcing time from Google's public NTP servers would produce compliant smeared leap-seconds but time sourced from members of pool.ntp.org likely will not.

About the Roughtime Protocol

Roughtime is a protocol that aims to achieve rough time synchronisation in a secure way that doesn't depend on any particular time server, and in such a way that, if a time server does misbehave, clients end up with cryptographic proof of it. It was created by Adam Langley and Robert Obryk.

Contributors

  • Stuart Stock (stuart {at} int08h.com)
  • Aaron Hill (aa1ronham {at} gmail.com)
  • Peter Todd (pete {at} petertodd.org)
  • Muncan90 (github.com/muncan90)
  • Zicklag (github.com/zicklag)
  • Greg at Unrelenting Tech (github.com/unrelentingtech)
  • Eric Swanson (github.com/lachesis)

Roughenough is copyright (c) 2017-2021 int08h LLC. All rights reserved.

int08h LLC licenses Roughenough (the "Software") to you under the Apache License, version 2.0 (the "License"); you may not use this Software except in compliance with the License. You may obtain a copy of the License from the LICENSE file included with the Software or at:

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Dependencies

~10–25MB
~423K SLoC