diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 88421016..314a9eb8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,6 +28,8 @@ jobs: - run: rustc --version - run: cargo build --release --workspace - run: (cd core && cargo build --features=json --release --all-targets) + - run: (cd daead && cargo build --features=boringssl --release) + - run: (cd examples/daead && cargo build --features=boringssl --release) test: runs-on: ubuntu-latest @@ -48,7 +50,7 @@ jobs: components: rustfmt override: true - run: rustc --version - - run: cargo test --all -- --nocapture + - run: cargo test --workspace -- --nocapture msrv: name: Rust ${{matrix.rust}} @@ -68,7 +70,7 @@ jobs: components: rustfmt override: true - run: rustc --version - - run: cargo build --release --workspace --all-features + - run: cargo test --release --workspace -- --nocapture formatting: runs-on: ubuntu-latest @@ -111,7 +113,9 @@ jobs: override: true components: rustfmt, clippy - run: rustc --version - - run: cargo clippy --all-features --all-targets -- -Dwarnings + - run: cargo clippy --all-targets -- -Dwarnings + - run: (cd core && cargo clippy --features=json -- -Dwarnings) + - run: (cd daead && cargo clippy --features=boringssl -- -Dwarnings) doc: runs-on: ubuntu-latest @@ -122,7 +126,7 @@ jobs: profile: minimal toolchain: stable - run: rustc --version - - run: cargo doc --no-deps --document-private-items --all-features + - run: cargo doc --no-deps --document-private-items --all-features --workspace --exclude tink-tests udeps: runs-on: ubuntu-latest diff --git a/Cargo.lock b/Cargo.lock index b146680e..cd242f80 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -155,6 +155,29 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "bindgen" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd4865004a46a0aafb2a0a5eb19d3c9fc46ee5f063a6cfc605c69ac9ecf5263d" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "clap", + "env_logger 0.8.4", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex 0.1.1", + "which 3.1.1", +] + [[package]] name = "bitflags" version = "1.2.1" @@ -182,6 +205,29 @@ dependencies = [ "generic-array", ] +[[package]] +name = "boring" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b556910067d022f92f220cf95827cd2e01a18d1482d3d1409fb80970775f7f81" +dependencies = [ + "bitflags", + "boring-sys", + "foreign-types", + "lazy_static", + "libc", +] + +[[package]] +name = "boring-sys" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4907c426f173847d574eb9afa27e492978f2e0fe069cf04d40dd72a81bd04a42" +dependencies = [ + "bindgen", + "cmake", +] + [[package]] name = "bstr" version = "0.2.13" @@ -218,6 +264,15 @@ version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" +[[package]] +name = "cexpr" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" version = "0.1.10" @@ -278,6 +333,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "clang-sys" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f54d78e30b388d4815220c8dd03fea5656b6c6d32adb59e89061552a102f8da1" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" version = "2.33.3" @@ -303,6 +369,15 @@ dependencies = [ "dbl", ] +[[package]] +name = "cmake" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb6210b637171dfba4cda12e579ac6dc73f5165ad56133e5d72ef3131f320855" +dependencies = [ + "cc", +] + [[package]] name = "const-oid" version = "0.5.2" @@ -529,6 +604,19 @@ dependencies = [ "zeroize", ] +[[package]] +name = "env_logger" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "env_logger" version = "0.9.0" @@ -803,6 +891,12 @@ dependencies = [ "polyval", ] +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + [[package]] name = "group" version = "0.9.0" @@ -1040,12 +1134,28 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "libc" version = "0.2.98" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" +[[package]] +name = "libloading" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a" +dependencies = [ + "cfg-if 1.0.0", + "winapi", +] + [[package]] name = "log" version = "0.4.14" @@ -1130,6 +1240,16 @@ dependencies = [ "tempfile", ] +[[package]] +name = "nom" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" +dependencies = [ + "memchr", + "version_check", +] + [[package]] name = "ntapi" version = "0.3.6" @@ -1224,6 +1344,12 @@ dependencies = [ "sha2", ] +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + [[package]] name = "percent-encoding" version = "2.1.0" @@ -1413,7 +1539,7 @@ dependencies = [ "prost", "prost-types", "tempfile", - "which", + "which 4.0.2", ] [[package]] @@ -1659,7 +1785,7 @@ dependencies = [ "hyper", "serde", "serde_json", - "shlex", + "shlex 1.0.0", "tokio", "zeroize", ] @@ -1704,6 +1830,12 @@ dependencies = [ "tokio", ] +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_version" version = "0.4.0" @@ -1879,6 +2011,12 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "shlex" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" + [[package]] name = "shlex" version = "1.0.0" @@ -2118,6 +2256,8 @@ version = "0.2.0" dependencies = [ "aead", "aes-siv", + "boring", + "cipher", "prost", "tink-core", "tink-proto", @@ -2210,7 +2350,7 @@ dependencies = [ name = "tink-testing-server" version = "0.2.0" dependencies = [ - "env_logger", + "env_logger 0.9.0", "futures", "log", "prost", @@ -2667,6 +2807,15 @@ dependencies = [ "untrusted", ] +[[package]] +name = "which" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724" +dependencies = [ + "libc", +] + [[package]] name = "which" version = "4.0.2" diff --git a/daead/Cargo.toml b/daead/Cargo.toml index 8920ac2e..7c54438b 100644 --- a/daead/Cargo.toml +++ b/daead/Cargo.toml @@ -9,9 +9,14 @@ repository = "https://github.com/project-oak/tink-rust" keywords = ["cryptography", "tink", "daead"] categories = ["cryptography"] +[features] +boringssl = ["boring"] + [dependencies] aead = { version = "^0.4.2", features = ["std"] } aes-siv = "^0.6" +boring = { version = "^1.1", optional = true } +cipher = "^0.3" prost = "^0.8" tink-core = "^0.2" tink-proto = "^0.2" diff --git a/daead/src/subtle/boring.rs b/daead/src/subtle/boring.rs new file mode 100644 index 00000000..0697655e --- /dev/null +++ b/daead/src/subtle/boring.rs @@ -0,0 +1,75 @@ +// Copyright 2020 The Tink-Rust Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License 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. +// +//////////////////////////////////////////////////////////////////////////////// + +//! Provides a Boring-SSL backed AES-256 cipher in a form suitable for +//! use with RustCrypto traits. + +use aes_siv::aead::generic_array::{ + typenum::{U16, U32, U8}, + GenericArray, +}; +use std::convert::TryInto; + +/// AES-256 block cipher +#[derive(Clone)] +pub struct Aes256 { + key: [u8; 32], +} + +impl cipher::NewBlockCipher for Aes256 { + type KeySize = U32; + + #[inline] + fn new(key: &GenericArray) -> Self { + Self { + key: key.as_slice().try_into().unwrap(/* safe: array size checked */), + } + } +} + +impl Aes256 { + fn process_block(&self, block: &mut GenericArray, mode: boring::symm::Mode) { + // To process a single block, use electronic code book mode (ECB) with no padding. + let cipher = boring::symm::Cipher::aes_256_ecb(); + let mut c = boring::symm::Crypter::new(cipher, mode, &self.key[..], None).unwrap(); // safe: size checked + c.pad(false); + let mut output = vec![0; block.len() + cipher.block_size()]; + // TODO(#10): investigate whether `boring` has an in-place operation. + let count = c.update(block, &mut output).unwrap(); // safe: pure optimism + let rest = c.finalize(&mut output[count..]).unwrap(); // safe: pure optimism + output.truncate(count + rest); + block[..16].copy_from_slice(&output) + } +} + +impl cipher::BlockCipher for Aes256 { + type BlockSize = U16; + type ParBlocks = U8; +} + +impl cipher::BlockEncrypt for Aes256 { + #[inline] + fn encrypt_block(&self, block: &mut GenericArray) { + self.process_block(block, boring::symm::Mode::Encrypt); + } +} + +impl cipher::BlockDecrypt for Aes256 { + #[inline] + fn decrypt_block(&self, block: &mut GenericArray) { + self.process_block(block, boring::symm::Mode::Decrypt); + } +} diff --git a/daead/src/subtle.rs b/daead/src/subtle/mod.rs similarity index 89% rename from daead/src/subtle.rs rename to daead/src/subtle/mod.rs index ee865f17..9e524a95 100644 --- a/daead/src/subtle.rs +++ b/daead/src/subtle/mod.rs @@ -16,12 +16,22 @@ //! Provides subtle implementations of the `DeterministicAEAD` primitive using AES-SIV. -use aes_siv::{aead::generic_array::GenericArray, siv::Aes256Siv}; +use aes_siv::aead::generic_array::GenericArray; use std::{cell::RefCell, rc::Rc}; use tink_core::{utils::wrap_err, TinkError}; const AES_BLOCK_SIZE: usize = 16; +#[cfg(not(feature = "boring"))] +use aes_siv::siv::Aes256Siv; + +// When the `boring` feature is enabled, use `boring` to provide basic AES block +// encryption, but still use RustCrypto traits to wrap this up into AES-SIV-CMAC. +#[cfg(feature = "boring")] +mod boring; +#[cfg(feature = "boring")] +type Aes256Siv = aes_siv::siv::CmacSiv; + /// `AesSiv` is an implementation of AES-SIV-CMAC as defined in /// [RFC 5297](https://tools.ietf.org/html/rfc5297). /// diff --git a/examples/daead/Cargo.toml b/examples/daead/Cargo.toml index dae5b95a..4ac2675c 100644 --- a/examples/daead/Cargo.toml +++ b/examples/daead/Cargo.toml @@ -6,6 +6,9 @@ edition = "2018" license = "Apache-2.0" publish = false +[features] +boringssl = ["tink-daead/boringssl"] + [dependencies] hex = "^0.4.3" tink-core = "^0.2" diff --git a/tests/Cargo.toml b/tests/Cargo.toml index f26983a6..8b31520e 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -10,6 +10,17 @@ keywords = ["cryptography", "tink", "testing"] categories = ["cryptography"] publish = false +[features] +default = ["kms"] +# The `tink-awskms` crates indirectly depend on OpenSSL, which cannot be linked at the +# same time as BoringSSL. Switch to BoringSSL mode with +# --no-default-features --features boringssl +# +# Note that this means that the features of this crate are *not* additive; turning on +# --all-features results in link failures. +boringssl = ["tink-daead/boringssl"] +kms = ["tink-awskms", "tink-gcpkms"] + [dependencies] base64 = "^0.13" ed25519-dalek = "^1.0.1" @@ -21,9 +32,11 @@ rand = "^0.7" regex = "^1.5.4" serde = { version = "^1.0.126", features = ["derive"] } serde_json = "^1.0.64" -tink-core = { version = "^0.2", features = ["insecure", "json"] } tink-aead = "^0.2" +tink-awskms = { version = "^0.2", optional = true } +tink-core = { version = "^0.2", features = ["insecure", "json"] } tink-daead = "^0.2" +tink-gcpkms = { version = "^0.2", optional = true } tink-mac = "^0.2" tink-proto = "^0.2" @@ -34,10 +47,11 @@ lazy_static = "^1.4" maplit = "^1.0.2" tempfile = "^3.2" tink-aead = "^0.2" -tink-awskms = "^0.2" tink-daead = "^0.2" -tink-gcpkms = "^0.2" tink-mac = "^0.2" tink-prf = "^0.2" tink-signature = "^0.2" tink-streaming-aead = "^0.2" + +[package.metadata.cargo-udeps.ignore] +normal = ["tink-awskms", "tink-gcpkms"] diff --git a/tests/src/lib.rs b/tests/src/lib.rs index db2a1354..f140ddfa 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -18,6 +18,9 @@ #![deny(broken_intra_doc_links)] +#[cfg(all(feature = "boringssl", feature = "kms"))] +compile_error!("features \"boringssl\" and \"kms\" cannot co-exist due to linker clashes between BoringSSL and OpenSSL"); + use generic_array::typenum::Unsigned; use p256::elliptic_curve; use serde::{Deserialize, Serialize}; diff --git a/tests/tests/aead/mod.rs b/tests/tests/aead/mod.rs index 8f98626a..6f99bf06 100644 --- a/tests/tests/aead/mod.rs +++ b/tests/tests/aead/mod.rs @@ -22,6 +22,7 @@ mod aes_gcm_siv_key_manager_test; mod chacha20poly1305_key_manager_test; mod integration_test; mod kms_envelope_aead_test; +#[cfg(feature = "kms")] mod kms_envelope_key_manager_test; mod xchacha20poly1305_key_manager_test; diff --git a/tests/tests/awskms_test.rs b/tests/tests/awskms_test.rs index 02feb473..a32b3727 100644 --- a/tests/tests/awskms_test.rs +++ b/tests/tests/awskms_test.rs @@ -14,4 +14,5 @@ // //////////////////////////////////////////////////////////////////////////////// +#[cfg(feature = "kms")] mod awskms; diff --git a/tests/tests/gcpkms_test.rs b/tests/tests/gcpkms_test.rs index 98cf1351..f56ab5c1 100644 --- a/tests/tests/gcpkms_test.rs +++ b/tests/tests/gcpkms_test.rs @@ -14,4 +14,5 @@ // //////////////////////////////////////////////////////////////////////////////// +#[cfg(feature = "kms")] mod gcpkms;