diff options
Diffstat (limited to 'src/rust')
-rw-r--r-- | src/rust/.cargo/config.in | 3 | ||||
-rw-r--r-- | src/rust/build.rs | 179 | ||||
-rw-r--r-- | src/rust/crypto/Cargo.toml | 6 | ||||
-rw-r--r-- | src/rust/crypto/digests/sha2.rs | 47 | ||||
-rw-r--r-- | src/rust/crypto/lib.rs | 26 | ||||
-rw-r--r-- | src/rust/crypto/rand/mod.rs | 10 | ||||
-rw-r--r-- | src/rust/crypto/rand/rng.rs | 4 | ||||
-rw-r--r-- | src/rust/external/crypto_digest.rs | 20 | ||||
-rw-r--r-- | src/rust/include.am | 1 | ||||
-rw-r--r-- | src/rust/protover/Cargo.toml | 1 | ||||
-rw-r--r-- | src/rust/tor_log/Cargo.toml | 1 | ||||
-rw-r--r-- | src/rust/tor_log/tor_log.rs | 4 |
12 files changed, 247 insertions, 55 deletions
diff --git a/src/rust/.cargo/config.in b/src/rust/.cargo/config.in index 301e7fdbe7..70481bbcbe 100644 --- a/src/rust/.cargo/config.in +++ b/src/rust/.cargo/config.in @@ -6,3 +6,6 @@ @RUST_DL@ [source.vendored-sources] @RUST_DL@ directory = '@TOR_RUST_DEPENDENCIES@' + +@RUST_WARN@ [build] +@RUST_WARN@ rustflags = [ "-D", "warnings" ]
\ No newline at end of file diff --git a/src/rust/build.rs b/src/rust/build.rs new file mode 100644 index 0000000000..b943aa5535 --- /dev/null +++ b/src/rust/build.rs @@ -0,0 +1,179 @@ +//! Build script for Rust modules in Tor. +//! +//! We need to use this because some of our Rust tests need to use some +//! of our C modules, which need to link some external libraries. +//! +//! This script works by looking at a "config.rust" file generated by our +//! configure script, and then building a set of options for cargo to pass to +//! the compiler. + +use std::collections::HashMap; +use std::env; +use std::fs::File; +use std::io::prelude::*; +use std::io; +use std::path::PathBuf; + +/// Wrapper around a key-value map. +struct Config( + HashMap<String,String> +); + +/// Locate a config.rust file generated by autoconf, starting in the OUT_DIR +/// location provided by cargo and recursing up the directory tree. Note that +/// we need to look in the OUT_DIR, since autoconf will place generated files +/// in the build directory. +fn find_cfg() -> io::Result<String> { + let mut path = PathBuf::from(env::var("OUT_DIR").unwrap()); + loop { + path.push("config.rust"); + if path.exists() { + return Ok(path.to_str().unwrap().to_owned()); + } + path.pop(); // remove config.rust + if ! path.pop() { // can't remove last part of directory + return Err(io::Error::new(io::ErrorKind::NotFound, + "No config.rust")); + } + } +} + +impl Config { + /// Find the config.rust file and try to parse it. + /// + /// The file format is a series of lines of the form KEY=VAL, with + /// any blank lines and lines starting with # ignored. + fn load() -> io::Result<Config> { + let path = find_cfg()?; + let f = File::open(&path)?; + let reader = io::BufReader::new(f); + let mut map = HashMap::new(); + for line in reader.lines() { + let s = line?; + if s.trim().starts_with("#") || s.trim() == "" { + continue; + } + let idx = match s.find("=") { + None => { + return Err(io::Error::new(io::ErrorKind::InvalidData, + "missing =")); + }, + Some(x) => x + }; + let (var,eq_val) = s.split_at(idx); + let val = &eq_val[1..]; + map.insert(var.to_owned(), val.to_owned()); + } + Ok(Config(map)) + } + + /// Return a reference to the value whose key is 'key'. + /// + /// Panics if 'key' is not found in the configuration. + fn get(&self, key : &str) -> &str { + self.0.get(key).unwrap() + } + + /// Add a dependency on a static C library that is part of Tor, by name. + fn component(&self, s : &str) { + println!("cargo:rustc-link-lib=static={}", s); + } + + /// Add a dependency on a native library that is not part of Tor, by name. + fn dependency(&self, s : &str) { + println!("cargo:rustc-link-lib={}", s); + } + + /// Add a link path, relative to Tor's build directory. + fn link_relpath(&self, s : &str) { + let builddir = self.get("BUILDDIR"); + println!("cargo:rustc-link-search=native={}/{}", builddir, s); + } + + /// Add an absolute link path. + fn link_path(&self, s : &str) { + println!("cargo:rustc-link-search=native={}", s); + } + + /// Parse the CFLAGS in s, looking for -l and -L items, and adding + /// rust configuration as appropriate. + fn from_cflags(&self, s : &str) { + let mut next_is_lib = false; + let mut next_is_path = false; + for ent in self.get(s).split_whitespace() { + if next_is_lib { + self.dependency(ent); + next_is_lib = false; + } else if next_is_path { + self.link_path(ent); + next_is_path = false; + } else if ent == "-l" { + next_is_lib = true; + } else if ent == "-L" { + next_is_path = true; + } else if ent.starts_with("-L") { + self.link_path(&ent[2..]); + } else if ent.starts_with("-l") { + self.dependency(&ent[2..]); + } + } + } +} + +pub fn main() { + let cfg = Config::load().unwrap(); + let package = env::var("CARGO_PKG_NAME").unwrap(); + + match package.as_ref() { + "crypto" => { + // Right now, I'm having a separate configuration for each Rust + // package, since I'm hoping we can trim them down. Once we have a + // second Rust package that needs to use this build script, let's + // extract some of this stuff into a module. + // + // This is a ridiculous amount of code to be pulling in just + // to test our crypto library: modularity would be our + // friend here. + cfg.from_cflags("TOR_LDFLAGS_zlib"); + cfg.from_cflags("TOR_LDFLAGS_openssl"); + cfg.from_cflags("TOR_LDFLAGS_libevent"); + + cfg.link_relpath("src/common"); + cfg.link_relpath("src/ext/keccak-tiny"); + cfg.link_relpath("src/ext/keccak-tiny"); + cfg.link_relpath("src/ext/ed25519/ref10"); + cfg.link_relpath("src/ext/ed25519/donna"); + cfg.link_relpath("src/trunnel"); + + // Note that we can't pull in "libtor-testing", or else we + // will have dependencies on all the other rust packages that + // tor uses. We must be careful with factoring and dependencies + // moving forward! + cfg.component("or-crypto-testing"); + cfg.component("or-ctime-testing"); + cfg.component("or-testing"); + cfg.component("or-event-testing"); + cfg.component("or-ctime-testing"); + cfg.component("curve25519_donna"); + cfg.component("keccak-tiny"); + cfg.component("ed25519_ref10"); + cfg.component("ed25519_donna"); + cfg.component("or-trunnel-testing"); + + cfg.from_cflags("TOR_ZLIB_LIBS"); + cfg.from_cflags("TOR_LIB_MATH"); + cfg.from_cflags("TOR_OPENSSL_LIBS"); + cfg.from_cflags("TOR_LIBEVENT_LIBS"); + cfg.from_cflags("TOR_LIB_WS32"); + cfg.from_cflags("TOR_LIB_GDI"); + cfg.from_cflags("TOR_LIB_USERENV"); + cfg.from_cflags("CURVE25519_LIBS"); + cfg.from_cflags("TOR_LZMA_LIBS"); + cfg.from_cflags("TOR_ZSTD_LIBS"); + cfg.from_cflags("LIBS"); + }, + _ => { + panic!("No configuration in build.rs for package {}", package); + } + } +} diff --git a/src/rust/crypto/Cargo.toml b/src/rust/crypto/Cargo.toml index 3d343344ae..869e0d6256 100644 --- a/src/rust/crypto/Cargo.toml +++ b/src/rust/crypto/Cargo.toml @@ -4,6 +4,7 @@ authors = ["The Tor Project", name = "crypto" version = "0.0.1" publish = false +build = "../build.rs" [lib] name = "crypto" @@ -13,7 +14,7 @@ crate_type = ["rlib", "staticlib"] [dependencies] libc = "=0.2.39" digest = "=0.7.2" -rand_core = "=0.2.0-pre.0" +rand_core = { version = "=0.2.0-pre.0", default-features = false } external = { path = "../external" } smartlist = { path = "../smartlist" } @@ -22,7 +23,6 @@ tor_log = { path = "../tor_log" } [dev-dependencies] rand = { version = "=0.5.0-pre.2", default-features = false } +rand_core = { version = "=0.2.0-pre.0", default-features = false } [features] -testing = ["tor_log/testing"] - diff --git a/src/rust/crypto/digests/sha2.rs b/src/rust/crypto/digests/sha2.rs index 1cbb6c581e..03e0843dc0 100644 --- a/src/rust/crypto/digests/sha2.rs +++ b/src/rust/crypto/digests/sha2.rs @@ -43,10 +43,10 @@ pub struct Sha256 { /// /// # Examples /// -/// ``` -/// use crypto::digest::Sha256; +/// ```rust,no_run +/// use crypto::digests::sha2::{Sha256, Digest}; /// -/// let hasher: Sha256 = Sha256::default(); +/// let mut hasher: Sha256 = Sha256::default(); /// ``` /// /// # Returns @@ -66,13 +66,13 @@ impl BlockInput for Sha256 { /// /// # Examples /// -/// ``` -/// use crypto::digest::Sha256; +/// ```rust,no_run +/// use crypto::digests::sha2::{Sha256, Digest}; /// -/// let hasher: Sha256 = Sha256::default(); +/// let mut hasher: Sha256 = Sha256::default(); /// -/// hasher.process(b"foo"); -/// hasher.process(b"bar"); +/// hasher.input(b"foo"); +/// hasher.input(b"bar"); /// ``` impl Input for Sha256 { fn process(&mut self, msg: &[u8]) { @@ -110,10 +110,10 @@ pub struct Sha512 { /// /// # Examples /// -/// ``` -/// use crypto::digest::Sha512; +/// ```rust,no_run +/// use crypto::digests::sha2::{Sha512, Digest}; /// -/// let hasher: Sha256 = Sha512::default(); +/// let mut hasher: Sha512 = Sha512::default(); /// ``` /// /// # Returns @@ -133,13 +133,13 @@ impl BlockInput for Sha512 { /// /// # Examples /// -/// ``` -/// use crypto::digest::Sha512; +/// ```rust,no_run +/// use crypto::digests::sha2::{Sha512, Digest}; /// -/// let hasher: Sha512 = Sha512::default(); +/// let mut hasher: Sha512 = Sha512::default(); /// -/// hasher.process(b"foo"); -/// hasher.process(b"bar"); +/// hasher.input(b"foo"); +/// hasher.input(b"bar"); /// ``` impl Input for Sha512 { fn process(&mut self, msg: &[u8]) { @@ -154,7 +154,7 @@ impl Input for Sha512 { // FIXME: Once const generics land in Rust, we should genericise calling // crypto_digest_get_digest in external::crypto_digest. impl FixedOutput for Sha512 { - type OutputSize = U32; + type OutputSize = U64; fn fixed_result(self) -> GenericArray<u8, Self::OutputSize> { let buffer: [u8; DIGEST512_LEN] = get_512_bit_digest(self.engine); @@ -178,6 +178,9 @@ mod test { fn sha256_digest() { let mut h: Sha256 = Sha256::new(); let mut result: [u8; DIGEST256_LEN] = [0u8; DIGEST256_LEN]; + let expected = [151, 223, 53, 136, 181, 163, 242, 75, 171, 195, + 133, 27, 55, 47, 11, 167, 26, 157, 205, 222, 212, + 59, 20, 185, 208, 105, 97, 191, 193, 112, 125, 157]; h.input(b"foo"); h.input(b"bar"); @@ -187,7 +190,7 @@ mod test { println!("{:?}", &result[..]); - assert_eq!(&result[..], &b"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"[..]); + assert_eq!(result, expected); } #[test] @@ -200,6 +203,12 @@ mod test { let mut h: Sha512 = Sha512::new(); let mut result: [u8; DIGEST512_LEN] = [0u8; DIGEST512_LEN]; + let expected = [203, 55, 124, 16, 176, 245, 166, 44, 128, 54, 37, 167, + 153, 217, 233, 8, 190, 69, 231, 103, 245, 209, 71, 212, 116, + 73, 7, 203, 5, 89, 122, 164, 237, 211, 41, 160, 175, 20, 122, + 221, 12, 244, 24, 30, 211, 40, 250, 30, 121, 148, 38, 88, 38, + 179, 237, 61, 126, 246, 240, 103, 202, 153, 24, 90]; + h.input(b"foo"); h.input(b"bar"); h.input(b"baz"); @@ -208,6 +217,6 @@ mod test { println!("{:?}", &result[..]); - assert_eq!(&result[..], &b"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"[..]); + assert_eq!(&result[..], &expected[..]); } } diff --git a/src/rust/crypto/lib.rs b/src/rust/crypto/lib.rs index e7e3b22e03..f72a859dd7 100644 --- a/src/rust/crypto/lib.rs +++ b/src/rust/crypto/lib.rs @@ -9,19 +9,19 @@ //! The `digests` module contains submodules for specific hash digests //! and extendable output functions. //! -//! ``` -//! use crypto::digests::sha256::Sha256; +//! ```rust,no_run +//! use crypto::digests::sha2::*; //! -//! let hasher: Sha256 = Sha256::default(); +//! let mut hasher: Sha256 = Sha256::default(); //! let mut result: [u8; 32] = [0u8; 32]; //! -//! hasher.input("foo"); -//! hasher.input("bar"); -//! hasher.input("baz"); +//! hasher.input(b"foo"); +//! hasher.input(b"bar"); +//! hasher.input(b"baz"); //! -//! result.copy_from_slice(hasher.result().as_bytes()); +//! result.copy_from_slice(hasher.result().as_slice()); //! -//! assert!(result == "XXX"); +//! assert!(result == [b'X'; DIGEST256_LEN]); //! ``` #[deny(missing_docs)] @@ -29,9 +29,17 @@ // External crates from cargo or TOR_RUST_DEPENDENCIES. extern crate digest; extern crate libc; +extern crate rand_core; + +// External dependencies for tests. +#[cfg(test)] +extern crate rand as rand_crate; // Our local crates. extern crate external; +#[cfg(not(test))] +#[macro_use] +extern crate tor_log; pub mod digests; // Unfortunately named "digests" plural to avoid name conflict with the digest crate - +pub mod rand; diff --git a/src/rust/crypto/rand/mod.rs b/src/rust/crypto/rand/mod.rs index 6b3058ad58..82d02a70bb 100644 --- a/src/rust/crypto/rand/mod.rs +++ b/src/rust/crypto/rand/mod.rs @@ -2,15 +2,5 @@ // Copyright (c) 2018, isis agora lovecruft // See LICENSE for licensing information -// External dependencies -#[cfg(test)] -extern crate rand; -extern crate rand_core; - // Internal dependencies -extern crate external; -#[cfg(not(test))] -#[macro_use] -extern crate tor_log; - pub mod rng; diff --git a/src/rust/crypto/rand/rng.rs b/src/rust/crypto/rand/rng.rs index d5fae8a32e..07a0a7bdc7 100644 --- a/src/rust/crypto/rand/rng.rs +++ b/src/rust/crypto/rand/rng.rs @@ -130,8 +130,8 @@ mod internal { #[cfg(test)] mod internal { // It doesn't matter if we pretend ChaCha is a CSPRNG in tests. - pub use rand::ChaChaRng as TorRng; - pub use rand::ChaChaRng as TorStrongestRng; + pub use rand_crate::ChaChaRng as TorRng; + pub use rand_crate::ChaChaRng as TorStrongestRng; } // Finally, expose the public functionality of whichever appropriate internal diff --git a/src/rust/external/crypto_digest.rs b/src/rust/external/crypto_digest.rs index bc49e6124c..3e8801f203 100644 --- a/src/rust/external/crypto_digest.rs +++ b/src/rust/external/crypto_digest.rs @@ -66,13 +66,6 @@ const DIGEST_SHA512: digest_algorithm_t = 2; const DIGEST_SHA3_256: digest_algorithm_t = 3; const DIGEST_SHA3_512: digest_algorithm_t = 4; -/// The total number of digest algorithms we currently support. -/// -/// We can't access these from Rust, because their definitions in C require -/// introspecting the `digest_algorithm_t` typedef, which is an enum, so we have -/// to redefine them here. -const N_DIGEST_ALGORITHMS: usize = DIGEST_SHA3_512 as usize + 1; - /// The number of hash digests we produce for a `common_digests_t`. /// /// We can't access these from Rust, because their definitions in C require @@ -117,6 +110,9 @@ struct common_digests_t { /// A `smartlist_t` is just an alias for the `#[repr(C)]` type `Stringlist`, to /// make it more clear that we're working with a smartlist which is owned by C. #[allow(non_camel_case_types)] +// BINDGEN_GENERATED: This type isn't actually bindgen generated, but the code +// below it which uses it is. As such, this comes up as "dead code" as well. +#[allow(dead_code)] type smartlist_t = Stringlist; /// All of the external functions from `src/common/crypto_digest.h`. @@ -144,7 +140,7 @@ extern "C" { fn crypto_digest_new() -> *mut crypto_digest_t; fn crypto_digest256_new(algorithm: digest_algorithm_t) -> *mut crypto_digest_t; fn crypto_digest512_new(algorithm: digest_algorithm_t) -> *mut crypto_digest_t; - fn crypto_digest_free(digest: *mut crypto_digest_t); + fn crypto_digest_free_(digest: *mut crypto_digest_t); fn crypto_digest_add_bytes(digest: *mut crypto_digest_t, data: *const c_char, len: size_t); fn crypto_digest_get_digest(digest: *mut crypto_digest_t, out: *mut c_char, out_len: size_t); fn crypto_digest_dup(digest: *const crypto_digest_t) -> *mut crypto_digest_t; @@ -296,6 +292,14 @@ impl CryptoDigest { } } +impl Drop for CryptoDigest { + fn drop(&mut self) { + unsafe { + crypto_digest_free_(self.0 as *mut crypto_digest_t); + } + } +} + /// Get the 256-bit digest output of a `crypto_digest_t`. /// /// # Inputs diff --git a/src/rust/include.am b/src/rust/include.am index 5fd9741e01..5e5b0b3faf 100644 --- a/src/rust/include.am +++ b/src/rust/include.am @@ -1,6 +1,7 @@ include src/rust/tor_rust/include.am EXTRA_DIST +=\ + src/rust/build.rs \ src/rust/Cargo.toml \ src/rust/Cargo.lock \ src/rust/.cargo/config.in \ diff --git a/src/rust/protover/Cargo.toml b/src/rust/protover/Cargo.toml index af1089c914..a8480e142a 100644 --- a/src/rust/protover/Cargo.toml +++ b/src/rust/protover/Cargo.toml @@ -4,7 +4,6 @@ version = "0.0.1" name = "protover" [features] -testing = ["tor_log/testing"] [dependencies] libc = "=0.2.39" diff --git a/src/rust/tor_log/Cargo.toml b/src/rust/tor_log/Cargo.toml index 971cd658b1..9d06299c05 100644 --- a/src/rust/tor_log/Cargo.toml +++ b/src/rust/tor_log/Cargo.toml @@ -9,7 +9,6 @@ path = "lib.rs" crate_type = ["rlib", "staticlib"] [features] -testing = [] [dependencies] libc = "0.2.39" diff --git a/src/rust/tor_log/tor_log.rs b/src/rust/tor_log/tor_log.rs index 1fdc0026bf..ad6725f0f2 100644 --- a/src/rust/tor_log/tor_log.rs +++ b/src/rust/tor_log/tor_log.rs @@ -88,7 +88,7 @@ pub fn tor_log_msg_impl( /// This implementation is used when compiling for actual use, as opposed to /// testing. -#[cfg(all(not(test), not(feature = "testing")))] +#[cfg(not(test))] pub mod log { use libc::{c_char, c_int}; use super::LogDomain; @@ -142,7 +142,7 @@ pub mod log { /// This module exposes no-op functionality for testing other Rust modules /// without linking to C. -#[cfg(any(test, feature = "testing"))] +#[cfg(test)] pub mod log { use libc::{c_char, c_int}; use super::LogDomain; |