diff --git a/.ci/gen-workflow-files.nu b/.ci/gen-workflow-files.nu index 8c1ea61..f1eaeec 100755 --- a/.ci/gen-workflow-files.nu +++ b/.ci/gen-workflow-files.nu @@ -1,6 +1,6 @@ #!/usr/bin/env nu -use log * +use std log # cd to git root cd (git rev-parse --show-toplevel) @@ -116,6 +116,7 @@ for system in ($targets | columns) { } } | filter {|it| $it.needed} | each {|it| job-id $system $it.name} + | sort ) mut new_job = { @@ -197,4 +198,4 @@ $cachix_workflow | to yaml | save --force .github/workflows/nix.yaml $release_workflow | to yaml | save --force .github/workflows/release.yaml log info "prettify generated yaml" -prettier -w .github/workflows/ \ No newline at end of file +prettier -w .github/workflows/ diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..219c13a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "cargo" + directory: "/" + schedule: + interval: "daily" diff --git a/.github/workflows/nix.yaml b/.github/workflows/nix.yaml index 2584025..14f8513 100644 --- a/.github/workflows/nix.yaml +++ b/.github/workflows/nix.yaml @@ -210,8 +210,8 @@ jobs: runs-on: - ubuntu-latest needs: - - x86_64-linux---rosenpass-static-oci-image - x86_64-linux---rosenpass-static + - x86_64-linux---rosenpass-static-oci-image steps: - uses: actions/checkout@v3 - uses: cachix/install-nix-action@v22 diff --git a/.github/workflows/qc.yaml b/.github/workflows/qc.yaml index 9710890..61e7eef 100644 --- a/.github/workflows/qc.yaml +++ b/.github/workflows/qc.yaml @@ -51,7 +51,7 @@ jobs: # liboqs requires quite a lot of stack memory, thus we adjust # the default stack size picked for new threads (which is used # by `cargo test`) to be _big enough_. Setting it to 8 MiB - - run: RUST_MIN_STACK=8388608 cargo bench --no-run --workspace + - run: RUST_MIN_STACK=8388608 cargo bench --workspace --exclude rosenpass-fuzzing cargo-audit: runs-on: ubuntu-latest diff --git a/Cargo.lock b/Cargo.lock index e3e4c18..620dc8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -108,9 +108,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" dependencies = [ "backtrace", ] @@ -167,9 +167,9 @@ dependencies = [ [[package]] name = "base64" -version = "0.21.5" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "bindgen" @@ -555,9 +555,9 @@ checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "env_logger" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" dependencies = [ "humantime", "is-terminal", @@ -821,9 +821,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "memchr" @@ -833,9 +833,9 @@ checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "memoffset" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ "autocfg", ] @@ -1011,9 +1011,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -1029,9 +1029,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -1293,18 +1293,18 @@ checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" [[package]] name = "serde" -version = "1.0.193" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", @@ -1385,9 +1385,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" -version = "2.0.39" +version = "2.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" dependencies = [ "proc-macro2", "quote", @@ -1417,18 +1417,18 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 4d6d5bf..a625694 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,12 +35,12 @@ test_bin = "0.4.0" libfuzzer-sys = "0.4" stacker = "0.1.15" doc-comment = "0.3.3" -base64 = "0.21.5" +base64 = "0.21.7" zeroize = "1.7.0" -memoffset = "0.9.0" -thiserror = "1.0.50" +memoffset = "0.9.1" +thiserror = "1.0.58" paste = "1.0.14" -env_logger = "0.10.1" +env_logger = "0.10.2" toml = "0.7.8" static_assertions = "1.1.0" allocator-api2 = "0.2.14" @@ -48,11 +48,11 @@ allocator-api2-tests = "0.2.14" memsec = "0.6.3" rand = "0.8.5" typenum = "1.17.0" -log = { version = "0.4.20" } +log = { version = "0.4.21" } clap = { version = "4.4.10", features = ["derive"] } -serde = { version = "1.0.193", features = ["derive"] } +serde = { version = "1.0.197", features = ["derive"] } arbitrary = { version = "1.3.2", features = ["derive"] } -anyhow = { version = "1.0.75", features = ["backtrace", "std"] } +anyhow = { version = "1.0.82", features = ["backtrace", "std"] } mio = { version = "0.8.11", features = ["net", "os-poll"] } oqs-sys = { version = "0.8", default-features = false, features = ['classic_mceliece', 'kyber'] } blake2 = "0.10.6" diff --git a/constant-time/src/compare.rs b/constant-time/src/compare.rs index d5e3605..301da6e 100644 --- a/constant-time/src/compare.rs +++ b/constant-time/src/compare.rs @@ -1,3 +1,18 @@ +use core::ptr; + +/// Little endian memcmp version of quinier/memsec +/// https://github.com/quininer/memsec/blob/bbc647967ff6d20d6dccf1c85f5d9037fcadd3b0/src/lib.rs#L30 +#[inline(never)] +pub unsafe fn memcmp_le(b1: *const u8, b2: *const u8, len: usize) -> i32 { + let mut res = 0; + for i in 0..len { + let diff = + i32::from(ptr::read_volatile(b1.add(i))) - i32::from(ptr::read_volatile(b2.add(i))); + res = (res & (((diff - 1) & !diff) >> 8)) | diff; + } + ((res - 1) >> 8) + (res >> 8) + 1 +} + /// compares two slices of memory content and returns an integer indicating the relationship between /// the slices /// @@ -20,5 +35,5 @@ #[inline] pub fn compare(a: &[u8], b: &[u8]) -> i32 { assert!(a.len() == b.len()); - unsafe { memsec::memcmp(a.as_ptr(), b.as_ptr(), a.len()) } + unsafe { memcmp_le(a.as_ptr(), b.as_ptr(), a.len()) } } diff --git a/flake.lock b/flake.lock index 6c2b1cc..de773f7 100644 --- a/flake.lock +++ b/flake.lock @@ -2,17 +2,15 @@ "nodes": { "fenix": { "inputs": { - "nixpkgs": [ - "nixpkgs" - ], + "nixpkgs": ["nixpkgs"], "rust-analyzer-src": "rust-analyzer-src" }, "locked": { - "lastModified": 1699770036, - "narHash": "sha256-bZmI7ytPAYLpyFNgj5xirDkKuAniOkj1xHdv5aIJ5GM=", + "lastModified": 1712298178, + "narHash": "sha256-590fpCPXYAkaAeBz/V91GX4/KGzPObdYtqsTWzT6AhI=", "owner": "nix-community", "repo": "fenix", - "rev": "81ab0b4f7ae9ebb57daa0edf119c4891806e4d3a", + "rev": "569b5b5781395da08e7064e825953c548c26af76", "type": "github" }, "original": { @@ -26,11 +24,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1694529238, - "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", "owner": "numtide", "repo": "flake-utils", - "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", "type": "github" }, "original": { @@ -41,9 +39,7 @@ }, "naersk": { "inputs": { - "nixpkgs": [ - "nixpkgs" - ] + "nixpkgs": ["nixpkgs"] }, "locked": { "lastModified": 1698420672, @@ -61,16 +57,18 @@ }, "nixpkgs": { "locked": { - "lastModified": 1698846319, - "narHash": "sha256-4jyW/dqFBVpWFnhl0nvP6EN4lP7/ZqPxYRjl6var0Oc=", + "lastModified": 1712168706, + "narHash": "sha256-XP24tOobf6GGElMd0ux90FEBalUtw6NkBSVh/RlA6ik=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "34bdaaf1f0b7fb6d9091472edc968ff10a8c2857", + "rev": "1487bdea619e4a7a53a4590c475deabb5a9d1bfb", "type": "github" }, "original": { - "id": "nixpkgs", - "type": "indirect" + "owner": "NixOS", + "ref": "nixos-23.11", + "repo": "nixpkgs", + "type": "github" } }, "root": { @@ -84,11 +82,11 @@ "rust-analyzer-src": { "flake": false, "locked": { - "lastModified": 1699715108, - "narHash": "sha256-yPozsobJU55gj+szgo4Lpcg1lHvGQYAT6Y4MrC80mWE=", + "lastModified": 1712156296, + "narHash": "sha256-St7ZQrkrr5lmQX9wC1ZJAFxL8W7alswnyZk9d1se3Us=", "owner": "rust-lang", "repo": "rust-analyzer", - "rev": "5fcf5289e726785d20d3aa4d13d90a43ed248e83", + "rev": "8e581ac348e223488622f4d3003cb2bd412bf27e", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 332e9eb..b7fc705 100644 --- a/flake.nix +++ b/flake.nix @@ -1,5 +1,6 @@ { inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11"; flake-utils.url = "github:numtide/flake-utils"; # for quicker rust builds @@ -318,6 +319,7 @@ cargo-release clippy nodePackages.prettier + nushell # for the .ci/gen-workflow-files.nu script rustfmt packages.proverif-patched ]; diff --git a/rosenpass/src/app_server.rs b/rosenpass/src/app_server.rs index 317d52f..e8f98d0 100644 --- a/rosenpass/src/app_server.rs +++ b/rosenpass/src/app_server.rs @@ -4,7 +4,7 @@ use anyhow::Result; use log::{debug, error, info, warn}; use mio::Interest; use mio::Token; -use rosenpass_util::file::fopen_w; +use rosenpass_util::file::{fopen_w, Visibility}; use std::cell::Cell; use std::io::Write; @@ -703,7 +703,7 @@ impl AppServer { // data will linger in the linux page cache anyways with the current // implementation, going to great length to erase the secret here is // not worth it right now. - b64_writer(fopen_w(of)?).write_all(key.secret())?; + b64_writer(fopen_w(of, Visibility::Secret)?).write_all(key.secret())?; let why = match why { KeyOutputReason::Exchanged => "exchanged", KeyOutputReason::Stale => "stale", diff --git a/rosenpass/src/cli.rs b/rosenpass/src/cli.rs index 1482cf1..c91e1e4 100644 --- a/rosenpass/src/cli.rs +++ b/rosenpass/src/cli.rs @@ -334,5 +334,5 @@ fn generate_and_save_keypair(secret_key: PathBuf, public_key: PathBuf) -> anyhow let mut spk = crate::protocol::SPk::random(); StaticKem::keygen(ssk.secret_mut(), spk.secret_mut())?; ssk.store_secret(secret_key)?; - spk.store_secret(public_key) + spk.store(public_key) } diff --git a/rosenpass/src/config.rs b/rosenpass/src/config.rs index 084c021..c1ab416 100644 --- a/rosenpass/src/config.rs +++ b/rosenpass/src/config.rs @@ -16,7 +16,7 @@ use std::{ }; use anyhow::{bail, ensure}; -use rosenpass_util::file::fopen_w; +use rosenpass_util::file::{fopen_w, Visibility}; use serde::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize)] @@ -151,7 +151,7 @@ impl Rosenpass { /// Commit the configuration to where it came from, overwriting the original file pub fn commit(&self) -> anyhow::Result<()> { - let mut f = fopen_w(&self.config_file_path)?; + let mut f = fopen_w(&self.config_file_path, Visibility::Public)?; f.write_all(toml::to_string_pretty(&self)?.as_bytes())?; self.store(&self.config_file_path) diff --git a/secret-memory/src/file.rs b/secret-memory/src/file.rs index f67bb52..78d5f22 100644 --- a/secret-memory/src/file.rs +++ b/secret-memory/src/file.rs @@ -4,4 +4,5 @@ pub trait StoreSecret { type Error; fn store_secret>(&self, path: P) -> Result<(), Self::Error>; + fn store>(&self, path: P) -> Result<(), Self::Error>; } diff --git a/secret-memory/src/secret.rs b/secret-memory/src/secret.rs index 0b2d993..9643603 100644 --- a/secret-memory/src/secret.rs +++ b/secret-memory/src/secret.rs @@ -16,6 +16,8 @@ use rosenpass_util::functional::mutating; use crate::alloc::{secret_box, SecretBox, SecretVec}; use crate::file::StoreSecret; +use rosenpass_util::file::{fopen_w, Visibility}; +use std::io::Write; // This might become a problem in library usage; it's effectively a memory // leak which probably isn't a problem right now because most memory will // be reused… @@ -272,7 +274,12 @@ impl StoreSecret for Secret { type Error = anyhow::Error; fn store_secret>(&self, path: P) -> anyhow::Result<()> { - std::fs::write(path, self.secret())?; + fopen_w(path, Visibility::Secret)?.write_all(self.secret())?; + Ok(()) + } + + fn store>(&self, path: P) -> anyhow::Result<()> { + fopen_w(path, Visibility::Public)?.write_all(self.secret())?; Ok(()) } } diff --git a/util/src/file.rs b/util/src/file.rs index 48f8eb5..b523220 100644 --- a/util/src/file.rs +++ b/util/src/file.rs @@ -1,17 +1,24 @@ use anyhow::ensure; use std::fs::File; use std::io::Read; +use std::os::unix::fs::OpenOptionsExt; use std::result::Result; use std::{fs::OpenOptions, path::Path}; +pub enum Visibility { + Public, + Secret, +} + /// Open a file writable -pub fn fopen_w>(path: P) -> std::io::Result { - OpenOptions::new() - .read(false) - .write(true) - .create(true) - .truncate(true) - .open(path) +pub fn fopen_w>(path: P, visibility: Visibility) -> std::io::Result { + let mut options = OpenOptions::new(); + options.create(true).write(true).read(false).truncate(true); + match visibility { + Visibility::Public => options.mode(0o644), + Visibility::Secret => options.mode(0o600), + }; + options.open(path) } /// Open a file readable pub fn fopen_r>(path: P) -> std::io::Result {