proper permission for secrets aka 0o600

When creating secret keys or use the out file feature, the material
shouldn't be readble to everyone by default.

Fix: #260

Signed-off-by: Paul Spooren <mail@aparcar.org>
This commit is contained in:
Paul Spooren
2024-03-13 16:23:30 +01:00
parent baa35af558
commit 40d955a156
6 changed files with 28 additions and 13 deletions

View File

@@ -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;
@@ -609,7 +609,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",

View File

@@ -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)
}

View File

@@ -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)

View File

@@ -4,4 +4,5 @@ pub trait StoreSecret {
type Error;
fn store_secret<P: AsRef<Path>>(&self, path: P) -> Result<(), Self::Error>;
fn store<P: AsRef<Path>>(&self, path: P) -> Result<(), Self::Error>;
}

View File

@@ -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<const N: usize> StoreSecret for Secret<N> {
type Error = anyhow::Error;
fn store_secret<P: AsRef<Path>>(&self, path: P) -> anyhow::Result<()> {
std::fs::write(path, self.secret())?;
fopen_w(path, Visibility::Secret)?.write_all(self.secret())?;
Ok(())
}
fn store<P: AsRef<Path>>(&self, path: P) -> anyhow::Result<()> {
fopen_w(path, Visibility::Public)?.write_all(self.secret())?;
Ok(())
}
}

View File

@@ -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<P: AsRef<Path>>(path: P) -> std::io::Result<File> {
OpenOptions::new()
.read(false)
.write(true)
.create(true)
.truncate(true)
.open(path)
pub fn fopen_w<P: AsRef<Path>>(path: P, visibility: Visibility) -> std::io::Result<File> {
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<P: AsRef<Path>>(path: P) -> std::io::Result<File> {