From d2b6b83950201d9d474f5d6c824a75b86899e342 Mon Sep 17 00:00:00 2001 From: Ramil_Algayev Date: Sun, 29 Dec 2024 06:37:54 +0400 Subject: [PATCH 1/3] this took forever --- dtrfs_api/Cargo.lock | 59 +++++++++++++---- dtrfs_api/Cargo.toml | 2 +- dtrfs_api/src/main.rs | 146 ++++++++++++++++++++++++++---------------- dtrfs_api/src/os.rs | 84 ++++++++++++++++-------- dtrfs_api/src/snp.rs | 27 ++++++-- 5 files changed, 218 insertions(+), 100 deletions(-) diff --git a/dtrfs_api/Cargo.lock b/dtrfs_api/Cargo.lock index f72473f..4c4db8a 100644 --- a/dtrfs_api/Cargo.lock +++ b/dtrfs_api/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "actix-codec" @@ -36,7 +36,7 @@ dependencies = [ "brotli", "bytes", "bytestring", - "derive_more", + "derive_more 0.99.18", "encoding_rs", "flate2", "futures-core", @@ -172,7 +172,7 @@ dependencies = [ "bytestring", "cfg-if", "cookie", - "derive_more", + "derive_more 0.99.18", "encoding_rs", "futures-core", "futures-util", @@ -258,12 +258,6 @@ dependencies = [ "alloc-no-stdlib", ] -[[package]] -name = "anyhow" -version = "1.0.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" - [[package]] name = "autocfg" version = "1.4.0" @@ -494,6 +488,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "cookie" version = "0.16.2" @@ -611,13 +614,35 @@ version = "0.99.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ - "convert_case", + "convert_case 0.4.0", "proc-macro2", "quote", "rustc_version", "syn", ] +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "convert_case 0.6.0", + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + [[package]] name = "digest" version = "0.10.7" @@ -667,9 +692,9 @@ name = "dtrfs_api" version = "0.1.0" dependencies = [ "actix-web", - "anyhow", "base64", "bincode", + "derive_more 1.0.0", "ed25519-dalek", "lazy_static", "regex", @@ -2175,6 +2200,18 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "untrusted" version = "0.9.0" diff --git a/dtrfs_api/Cargo.toml b/dtrfs_api/Cargo.toml index f01b59f..f73c6d9 100644 --- a/dtrfs_api/Cargo.toml +++ b/dtrfs_api/Cargo.toml @@ -4,9 +4,9 @@ version = "0.1.0" edition = "2021" [dependencies] -anyhow = "1.0.93" base64 = "0.22.1" bincode = "1.3.3" +derive_more = {version = "1.0.0", features = ["full"] } regex = "1.11.1" sev = { version = "4.0", default-features = false, features = ['crypto_nossl','snp'] } ed25519-dalek = { version = "2.1.1", features = ["pem", "pkcs8"] } diff --git a/dtrfs_api/src/main.rs b/dtrfs_api/src/main.rs index cd11718..7c09e0b 100644 --- a/dtrfs_api/src/main.rs +++ b/dtrfs_api/src/main.rs @@ -1,8 +1,10 @@ mod os; mod snp; -use actix_web::{get, post, web, App, HttpRequest, HttpResponse, HttpServer}; +use crate::os::OsError; +use actix_web::{get, post, web, App, Error, HttpRequest, HttpResponse, HttpServer, ResponseError}; use base64::prelude::{Engine, BASE64_URL_SAFE}; +use derive_more::derive::{Display, Error, From}; use ed25519_dalek::{pkcs8::DecodePublicKey, Signature, Verifier, VerifyingKey}; use lazy_static::lazy_static; use regex::Regex; @@ -15,50 +17,96 @@ use std::{ io::{BufReader, Read}, }; +#[derive(Debug, Display, From, Error)] +pub enum DtrfsError { + #[display("OS error: {_0}")] + OsError(#[from] OsError), + #[display("SNP error: {_0}")] + SnpError(#[from] snp::SNPError), + #[display("Could not find admin key in cmdline")] + AdminKeyNotFound, + #[display("Could not parse verifying key: {_0}")] + VerifyingKeyParsingError(ed25519_dalek::pkcs8::spki::Error), + #[display("Could not get signature from request")] + SignatureNotFound, + #[display("Base64 decoding error: {_0}")] + Base64Error(base64::DecodeError), + #[display("IO error: {_0}")] + IoError(#[from] std::io::Error), + #[display("Error slicing into bytes: {_0}")] + SliceError(std::array::TryFromSliceError), + #[display("Error verifying signature: {_0}")] + SignatureVerificationError(ed25519_dalek::SignatureError), +} + +impl ResponseError for DtrfsError { + fn error_response(&self) -> HttpResponse { + match self { + error => HttpResponse::InternalServerError().body(format!("{}", error)), + } + } +} + const CRT_FILE: &str = "/tmp/certs/dtrfs_api.crt"; const KEY_FILE: &str = "/tmp/certs/dtrfs_api.key"; const CMDLINE_FILE: &str = "/proc/cmdline"; lazy_static! { - static ref SNP_REPORT: String = snp::get_report_as_base64(get_cert_hash()).unwrap(); + static ref SNP_REPORT: String = match get_cert_hash() + .and_then(|hash| snp::get_report_as_base64(hash).map_err(|err| err.into())) + { + Ok(report) => report, + Err(e) => { + eprintln!("Failed to get SNP report: {}", e); + String::new() + } + }; static ref CRT_CONTENTS: String = { let mut msg = String::new(); - let _ = BufReader::new(File::open(CRT_FILE).unwrap()).read_to_string(&mut msg); + if let Err(e) = + File::open(CRT_FILE).and_then(|file| BufReader::new(file).read_to_string(&mut msg)) + { + eprintln!("Failed to read certificate file: {}", e); + } msg }; static ref CMDLINE: String = { let mut cmdline = String::new(); - let _ = BufReader::new(File::open(CMDLINE_FILE).unwrap()).read_to_string(&mut cmdline); + if let Err(e) = File::open(CMDLINE_FILE) + .and_then(|file| BufReader::new(file).read_to_string(&mut cmdline)) + { + eprintln!("Failed to read cmdline file: {}", e); + } cmdline }; } -fn get_cert_hash() -> [u8; 64] { +fn get_cert_hash() -> Result<[u8; 64], DtrfsError> { let mut hasher = Sha3_512::new(); - let crt = File::open(CRT_FILE).expect("Could not open crt file."); + let crt = File::open(CRT_FILE)?; let mut buf_reader = BufReader::new(crt); let mut buffer = Vec::new(); - buf_reader.read_to_end(&mut buffer).expect("Could not read certificate."); + buf_reader.read_to_end(&mut buffer)?; hasher.update(buffer); - let crt_hash = hasher.finalize(); - crt_hash.into() + let crt_hash: [u8; 64] = hasher.finalize().into(); + Ok(crt_hash) } -fn verifying_key() -> Result> { - let re = Regex::new(r"detee_admin=([A-Za-z0-9+/=]+)").unwrap(); +fn verifying_key() -> Result { + let re = Regex::new(r"detee_admin=([A-Za-z0-9+/=]+)").unwrap(); //unwrap here is ok since the regex is hardcoded and can only fail if the regex is bigger than the configured size limit via RegexBuilder::size_limit let key_str = re.find(&CMDLINE).map(|m| m.as_str()).unwrap_or(""); let key_pem = format!( "-----BEGIN PUBLIC KEY-----\n{}\n-----END PUBLIC KEY-----\n", - key_str.strip_prefix("detee_admin=").ok_or("Could not get admin key from cmdline")? + key_str.strip_prefix("detee_admin=").ok_or(DtrfsError::AdminKeyNotFound)? ); Ok(VerifyingKey::from_public_key_pem(&key_pem)?) } -fn verify(req: &HttpRequest) -> Result<(), Box> { +fn verify(req: &HttpRequest) -> Result<(), DtrfsError> { let signature = req .headers() .get("ed25519-signature") - .ok_or_else(|| "Did not find ed25519-signature header")?; + .ok_or_else(|| DtrfsError::SignatureNotFound)?; let signature: &[u8] = &BASE64_URL_SAFE.decode(signature)?; let signature = Signature::from_bytes(signature.try_into()?); @@ -89,14 +137,14 @@ struct InstallForm { // TODO: QA this function to make sure we don't accidentally allow empty string keyfile #[post("/install")] -async fn post_install_form(req: HttpRequest, form: web::Form) -> HttpResponse { - if let Err(e) = verify(&req) { - return HttpResponse::BadRequest().body(format!("Signature verification failed: {}", e)); - }; - match os::encrypt_and_install_os(&form.url, &form.sha, &form.keyfile) { - Ok(s) => HttpResponse::Ok().body(s), - Err(e) => HttpResponse::InternalServerError().body(format!("{e:?}")), - } +async fn post_install_form( + req: HttpRequest, + form: web::Form, +) -> Result { + verify(&req)?;// TODO: This is temporary, we need to merget from the other branch + os::encrypt_and_install_os(&form.url, &form.sha, &form.keyfile) + .map(|msg| HttpResponse::Ok().body(msg)) + .map_err(|e| DtrfsError::OsError(e).into()) } #[derive(Deserialize)] @@ -106,24 +154,18 @@ struct DecryptForm { // TODO: QA this function to make sure we don't accidentally allow empty string keyfile #[post("/decrypt")] -async fn post_decrypt_form(req: HttpRequest, form: web::Form) -> HttpResponse { - if let Err(e) = verify(&req) { - return HttpResponse::BadRequest().body(format!("Signature verification failed: {}", e)); - }; - let decrypt_result = os::try_backup_keyfile(&form.keyfile); - if let Err(decryption_error) = decrypt_result { - return HttpResponse::BadRequest() - .body(format!("Could not decrypt root: {decryption_error:?}")); - } - let hot_key_result = os::replace_hot_keyfile(); - HttpResponse::Ok().body(format!("{:?}\n{:?}", decrypt_result, hot_key_result)) +async fn post_decrypt_form(req: HttpRequest, form: web::Form) -> Result { + verify(&req)?; + + let decrypt_result = os::try_backup_keyfile(&form.keyfile).map_err(DtrfsError::from)?; + let hot_key_result = os::replace_hot_keyfile().map_err(DtrfsError::from)?; + + Ok(HttpResponse::Ok().body(format!("{:?}\n{:?}", decrypt_result, hot_key_result))) } #[post("/switch_root")] -async fn post_process_exit(req: HttpRequest) -> HttpResponse { - if let Err(e) = verify(&req) { - return HttpResponse::BadRequest().body(format!("Signature verification failed: {}", e)); - }; +async fn post_process_exit(req: HttpRequest) -> Result { + verify(&req)?; std::process::exit(0); } @@ -133,26 +175,22 @@ struct SSHKeyForm { } #[get("/ssh_key")] -async fn get_ssh_keys(req: HttpRequest) -> HttpResponse { - if let Err(e) = verify(&req) { - return HttpResponse::BadRequest().body(format!("Signature verification failed: {}", e)); - }; - match os::list_ssh_keys() { - Ok(keys) => HttpResponse::Ok().body(keys), - Err(e) => HttpResponse::BadRequest().body(format!("{e:?}")), - } +async fn get_ssh_keys(req: HttpRequest) -> Result { + verify(&req)?; + os::list_ssh_keys() + .map(|keys| HttpResponse::Ok().body(keys)) + .map_err(|e| DtrfsError::OsError(e).into()) } #[post("/ssh_key")] -async fn post_ssh_key(req: HttpRequest, form: web::Form) -> HttpResponse { - if let Err(e) = verify(&req) { - return HttpResponse::BadRequest().body(format!("Signature verification failed: {}", e)); - }; +async fn post_ssh_key( + req: HttpRequest, + form: web::Form, +) -> Result { + verify(&req)?; let ssh_key = &form.ssh_key; - match os::add_ssh_key(ssh_key) { - Ok(()) => HttpResponse::Ok().body("Key added to authorized_keys"), - Err(e) => HttpResponse::BadRequest().body(format!("{e:?}")), - } + os::add_ssh_key(ssh_key).map_err(DtrfsError::from)?; + Ok(HttpResponse::Ok().body("SSH key added successfully")) } fn load_rustls_config() -> rustls::ServerConfig { @@ -183,7 +221,7 @@ async fn main() -> std::io::Result<()> { Ok(_) => { println!("Hot decryption successful. Booting OS..."); return Ok(()); - }, + } Err(e) => { println!("Hot decryption failed: {e:?}"); } diff --git a/dtrfs_api/src/os.rs b/dtrfs_api/src/os.rs index 7ed90b9..3dcd1e3 100644 --- a/dtrfs_api/src/os.rs +++ b/dtrfs_api/src/os.rs @@ -1,13 +1,45 @@ -use crate::snp::get_derived_key; -use anyhow::{anyhow, Result}; -use base64::prelude::{Engine, BASE64_URL_SAFE}; +use crate::snp::{get_derived_key, SNPError}; +use base64::{ + prelude::{Engine, BASE64_URL_SAFE}, + DecodeError, +}; +use derive_more::{Display, Error, From}; use std::{ fs::File, - io::{BufRead, BufReader, Write}, + io::{self, BufRead, BufReader, Write}, path::Path, process::Command, + string::FromUtf8Error, }; +#[derive(Debug, Display, Error, From)] +pub enum OsError { + #[display( + "OS installation script failed.\nScript stdout:\n{stdout}\nScript stderr:\n{stderr}" + )] + InstallationFailed { stdout: String, stderr: String }, + #[display("Could not decrypt disk.")] + DecryptionFailed, + #[display("Could not mount /dev/mapper/root to /mnt")] + MountFailed, + #[display("Could not try hot keyfile: {_0}")] + TryHotKeyfileFailed(#[from] SNPError), + #[display("Could not replace hot keyfile using SNP KDF.")] + ReplaceHotKeyfileFailed, + #[display("Operating system not mounted. Please install OS or decrypt existing OS.")] + OsNotMounted, + #[display("Supplied key is expected to have at least two words.")] + InvalidSshKey, + #[display("authorized_keys already contains {err}")] + SshKeyAlreadyExists { err: String }, + #[display("I/O error: {_0}")] + IoError(#[from] io::Error), + #[display("Base64 decoding error: {_0}")] + Base64Error(#[from] DecodeError), + #[display("UTF-8 conversion error: {_0}")] + Utf8Error(#[from] FromUtf8Error), +} + const SNP_KEYFILE_PATH: &str = "/tmp/detee_snp_keyfile"; const BACKUP_KEYFILE_PATH: &str = "/tmp/detee_backup_keyfile"; @@ -15,7 +47,7 @@ pub fn encrypt_and_install_os( install_url: &str, install_sha: &str, keyfile: &str, -) -> Result { +) -> Result { let binary_keyfile = BASE64_URL_SAFE.decode(keyfile)?; std::fs::write(BACKUP_KEYFILE_PATH, binary_keyfile)?; // this path is hardcoded also in the initrd creation script @@ -27,14 +59,14 @@ pub fn encrypt_and_install_os( .output()?; if !install_result.status.success() { - return Err(anyhow!( - "OS installation script failed.\nScript stdout:\n{}\nScript stderr:\n{}", - String::from_utf8(install_result.stdout) + return Err(OsError::InstallationFailed { + stdout: String::from_utf8(install_result.stdout) .unwrap_or("Could not grab stdout from installation script.".to_string()), - String::from_utf8(install_result.stderr) + stderr: String::from_utf8(install_result.stderr) .unwrap_or("Could not grab stderr from installation script.".to_string()), - )); + }); } + Ok(format!( "Successfully installed OS. Script stdout:\n{}\nScript stderr:\n{}", String::from_utf8(install_result.stdout) @@ -44,21 +76,21 @@ pub fn encrypt_and_install_os( )) } -pub fn try_hot_keyfile() -> Result<()> { +pub fn try_hot_keyfile() -> Result<(), OsError> { let hot_key = get_derived_key()?; std::fs::write(SNP_KEYFILE_PATH, hot_key)?; decrypt_and_mount(SNP_KEYFILE_PATH)?; Ok(()) } -pub fn try_backup_keyfile(keyfile: &str) -> Result { +pub fn try_backup_keyfile(keyfile: &str) -> Result { let binary_keyfile = BASE64_URL_SAFE.decode(keyfile)?; std::fs::write(BACKUP_KEYFILE_PATH, binary_keyfile)?; decrypt_and_mount(BACKUP_KEYFILE_PATH)?; Ok("Succesfully mounted /mnt using backup keyfile.".to_string()) } -fn decrypt_and_mount(keyfile_path: &str) -> Result<()> { +fn decrypt_and_mount(keyfile_path: &str) -> Result<(), OsError> { let decryption_result = Command::new("cryptsetup") .arg("open") .arg("--key-file") @@ -67,27 +99,27 @@ fn decrypt_and_mount(keyfile_path: &str) -> Result<()> { .arg("root") .output()?; if !decryption_result.status.success() { - return Err(anyhow!("Could not decrypt disk.")); + return Err(OsError::DecryptionFailed); } let mount_result = Command::new("mount").arg("/dev/mapper/root").arg("/mnt").output()?; if !mount_result.status.success() { - return Err(anyhow!("Could not mount /dev/mapper/root to /mnt")); + return Err(OsError::MountFailed); } Ok(()) } -pub fn replace_hot_keyfile() -> Result { +pub fn replace_hot_keyfile() -> Result { let _delete_old_keyfile = Command::new("cryptsetup") .arg("luksKillSlot") .arg("-d") .arg(BACKUP_KEYFILE_PATH) .arg("/dev/vda1") .arg("1") - .output(); + .output()?; let meta = std::fs::metadata(SNP_KEYFILE_PATH)?; if meta.len() == 0 { - return Err(anyhow!("Could not replace hot keyfile using SNP KDF.")); + return Err(OsError::ReplaceHotKeyfileFailed); } let _add_hot_keyfile = Command::new("cryptsetup") @@ -97,28 +129,26 @@ pub fn replace_hot_keyfile() -> Result { .arg("--new-keyfile") .arg(SNP_KEYFILE_PATH) .arg("/dev/vda1") - .output(); + .output()?; Ok("Succesfully replaced hot keyfile using SNP KDF.".to_string()) } -pub fn add_ssh_key(key: &str) -> Result<()> { +pub fn add_ssh_key(key: &str) -> Result<(), OsError> { use std::os::unix::fs::PermissionsExt; if !Path::new("/mnt/etc/os-release").try_exists().is_ok_and(|found| found == true) { - return Err(anyhow!( - "Operating system not mounted. Please install OS or decrypt existing OS." - )); + return Err(OsError::OsNotMounted); } let encoded_key: Vec<&str> = key.split(" ").collect(); if encoded_key.len() < 2 { - return Err(anyhow!("Supplied key is expected to have at least two words.")); + return Err(OsError::InvalidSshKey); } - if let Ok(keys) = File::open("/mnt/.ssh/authorized_keys") { + if let Ok(keys) = File::open("/mnt/root/.ssh/authorized_keys") { let mut buffered = BufReader::new(keys).lines(); while let Some(Ok(k)) = buffered.next() { if k.contains(encoded_key[1]) { - return Err(anyhow!("authorized_keys already contains {key}")); + return Err(OsError::SshKeyAlreadyExists { err: key.to_string() }); } } } else { @@ -142,6 +172,6 @@ pub fn add_ssh_key(key: &str) -> Result<()> { Ok(()) } -pub fn list_ssh_keys() -> Result { +pub fn list_ssh_keys() -> Result { Ok(std::fs::read_to_string("/mnt/root/.ssh/authorized_keys")?) } diff --git a/dtrfs_api/src/snp.rs b/dtrfs_api/src/snp.rs index e3d57ba..5705f23 100644 --- a/dtrfs_api/src/snp.rs +++ b/dtrfs_api/src/snp.rs @@ -1,18 +1,31 @@ -use anyhow::{Context, Result}; -use sev::firmware::guest::{AttestationReport, DerivedKey, Firmware, GuestFieldSelect}; use base64::prelude::{Engine, BASE64_URL_SAFE}; +use derive_more::{Display, Error, From}; +use sev::error::UserApiError; +use sev::firmware::guest::{AttestationReport, DerivedKey, Firmware, GuestFieldSelect}; -fn request_hardware_report(data: [u8; 64]) -> Result { - let mut fw = Firmware::open().context("unable to open /dev/sev-guest")?; - fw.get_report(None, Some(data), Some(0)).context("unable to fetch attestation report") +#[derive(Debug, Display, From, Error)] +pub enum SNPError { + #[display("Could not parse the derived key: {_0}")] + KeyParsingError(#[from] std::num::ParseIntError), + #[display("authorized_keys already contains: {_0}")] + UserApiError(#[from] UserApiError), + #[display("I/O error: {_0}")] + FirmwareIOError(#[from] std::io::Error), + #[display("bincode Base64 decoding error: {_0}")] + Base64Error(#[from] bincode::Error), } -pub fn get_report_as_base64(data: [u8; 64]) -> Result { +fn request_hardware_report(data: [u8; 64]) -> Result { + let mut fw = Firmware::open()?; + Ok(fw.get_report(None, Some(data), Some(0))?) +} + +pub fn get_report_as_base64(data: [u8; 64]) -> Result { let report = request_hardware_report(data)?; Ok(BASE64_URL_SAFE.encode(bincode::serialize(&report)?)) } -pub fn get_derived_key() -> Result { +pub fn get_derived_key() -> Result { let mut fw = Firmware::open()?; let request = DerivedKey::new(false, GuestFieldSelect(u64::from_str_radix("11111", 2)?), 1, 0, 0); -- 2.43.0 From 559c761a3e2da9e413bd5cf105327a5f951bb77b Mon Sep 17 00:00:00 2001 From: Ramil_Algayev Date: Mon, 30 Dec 2024 05:54:50 +0400 Subject: [PATCH 2/3] fixed the lazy_static part --- dtrfs_api/src/main.rs | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/dtrfs_api/src/main.rs b/dtrfs_api/src/main.rs index 7c09e0b..4e31bea 100644 --- a/dtrfs_api/src/main.rs +++ b/dtrfs_api/src/main.rs @@ -52,31 +52,15 @@ const KEY_FILE: &str = "/tmp/certs/dtrfs_api.key"; const CMDLINE_FILE: &str = "/proc/cmdline"; lazy_static! { - static ref SNP_REPORT: String = match get_cert_hash() - .and_then(|hash| snp::get_report_as_base64(hash).map_err(|err| err.into())) - { - Ok(report) => report, - Err(e) => { - eprintln!("Failed to get SNP report: {}", e); - String::new() - } - }; + static ref SNP_REPORT: String = snp::get_report_as_base64(get_cert_hash().unwrap()).unwrap(); static ref CRT_CONTENTS: String = { let mut msg = String::new(); - if let Err(e) = - File::open(CRT_FILE).and_then(|file| BufReader::new(file).read_to_string(&mut msg)) - { - eprintln!("Failed to read certificate file: {}", e); - } + let _ = BufReader::new(File::open(CRT_FILE).unwrap()).read_to_string(&mut msg); msg }; static ref CMDLINE: String = { let mut cmdline = String::new(); - if let Err(e) = File::open(CMDLINE_FILE) - .and_then(|file| BufReader::new(file).read_to_string(&mut cmdline)) - { - eprintln!("Failed to read cmdline file: {}", e); - } + let _ = BufReader::new(File::open(CMDLINE_FILE).unwrap()).read_to_string(&mut cmdline); cmdline }; } -- 2.43.0 From 97cab04188a5e297f611448b24249b93ee29d92c Mon Sep 17 00:00:00 2001 From: Ramil_Algayev Date: Fri, 10 Jan 2025 21:20:03 +0400 Subject: [PATCH 3/3] switched to thiserror --- dtrfs_api/Cargo.lock | 75 +++++++++++++++---------------------------- dtrfs_api/Cargo.toml | 2 +- dtrfs_api/src/main.rs | 30 ++++++++--------- dtrfs_api/src/os.rs | 26 +++++++-------- dtrfs_api/src/snp.rs | 12 +++---- 5 files changed, 61 insertions(+), 84 deletions(-) diff --git a/dtrfs_api/Cargo.lock b/dtrfs_api/Cargo.lock index 4c4db8a..4be9e0f 100644 --- a/dtrfs_api/Cargo.lock +++ b/dtrfs_api/Cargo.lock @@ -36,7 +36,7 @@ dependencies = [ "brotli", "bytes", "bytestring", - "derive_more 0.99.18", + "derive_more", "encoding_rs", "flate2", "futures-core", @@ -172,7 +172,7 @@ dependencies = [ "bytestring", "cfg-if", "cookie", - "derive_more 0.99.18", + "derive_more", "encoding_rs", "futures-core", "futures-util", @@ -488,15 +488,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" -[[package]] -name = "convert_case" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "cookie" version = "0.16.2" @@ -614,35 +605,13 @@ version = "0.99.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ - "convert_case 0.4.0", + "convert_case", "proc-macro2", "quote", "rustc_version", "syn", ] -[[package]] -name = "derive_more" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" -dependencies = [ - "derive_more-impl", -] - -[[package]] -name = "derive_more-impl" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" -dependencies = [ - "convert_case 0.6.0", - "proc-macro2", - "quote", - "syn", - "unicode-xid", -] - [[package]] name = "digest" version = "0.10.7" @@ -694,7 +663,6 @@ dependencies = [ "actix-web", "base64", "bincode", - "derive_more 1.0.0", "ed25519-dalek", "lazy_static", "regex", @@ -703,6 +671,7 @@ dependencies = [ "serde", "sev", "sha3", + "thiserror 2.0.10", ] [[package]] @@ -1626,7 +1595,7 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -2051,7 +2020,16 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3ac7f54ca534db81081ef1c1e7f6ea8a3ef428d2fc069097c079443d24124d3" +dependencies = [ + "thiserror-impl 2.0.10", ] [[package]] @@ -2065,6 +2043,17 @@ dependencies = [ "syn", ] +[[package]] +name = "thiserror-impl" +version = "2.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e9465d30713b56a37ede7185763c3492a91be2f5fa68d958c44e41ab9248beb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "time" version = "0.3.36" @@ -2200,18 +2189,6 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - [[package]] name = "untrusted" version = "0.9.0" diff --git a/dtrfs_api/Cargo.toml b/dtrfs_api/Cargo.toml index f73c6d9..a99a283 100644 --- a/dtrfs_api/Cargo.toml +++ b/dtrfs_api/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] base64 = "0.22.1" bincode = "1.3.3" -derive_more = {version = "1.0.0", features = ["full"] } +thiserror = "2.0.10" regex = "1.11.1" sev = { version = "4.0", default-features = false, features = ['crypto_nossl','snp'] } ed25519-dalek = { version = "2.1.1", features = ["pem", "pkcs8"] } diff --git a/dtrfs_api/src/main.rs b/dtrfs_api/src/main.rs index 4e31bea..0704556 100644 --- a/dtrfs_api/src/main.rs +++ b/dtrfs_api/src/main.rs @@ -4,7 +4,7 @@ mod snp; use crate::os::OsError; use actix_web::{get, post, web, App, Error, HttpRequest, HttpResponse, HttpServer, ResponseError}; use base64::prelude::{Engine, BASE64_URL_SAFE}; -use derive_more::derive::{Display, Error, From}; +use thiserror::Error; use ed25519_dalek::{pkcs8::DecodePublicKey, Signature, Verifier, VerifyingKey}; use lazy_static::lazy_static; use regex::Regex; @@ -17,26 +17,26 @@ use std::{ io::{BufReader, Read}, }; -#[derive(Debug, Display, From, Error)] +#[derive(Debug, Error)] pub enum DtrfsError { - #[display("OS error: {_0}")] + #[error("OS error: {0}")] OsError(#[from] OsError), - #[display("SNP error: {_0}")] + #[error("SNP error: {0}")] SnpError(#[from] snp::SNPError), - #[display("Could not find admin key in cmdline")] + #[error("Could not find admin key in cmdline")] AdminKeyNotFound, - #[display("Could not parse verifying key: {_0}")] - VerifyingKeyParsingError(ed25519_dalek::pkcs8::spki::Error), - #[display("Could not get signature from request")] + #[error("Could not parse verifying key: {0}")] + VerifyingKeyParsingError(#[from] ed25519_dalek::pkcs8::spki::Error), + #[error("Could not get signature from request")] SignatureNotFound, - #[display("Base64 decoding error: {_0}")] - Base64Error(base64::DecodeError), - #[display("IO error: {_0}")] + #[error("Base64 decoding error: {0}")] + Base64Error(#[from] base64::DecodeError), + #[error("IO error: {0}")] IoError(#[from] std::io::Error), - #[display("Error slicing into bytes: {_0}")] - SliceError(std::array::TryFromSliceError), - #[display("Error verifying signature: {_0}")] - SignatureVerificationError(ed25519_dalek::SignatureError), + #[error("Error slicing into bytes: {0}")] + SliceError(#[from] std::array::TryFromSliceError), + #[error("Error verifying signature: {0}")] + SignatureVerificationError(#[from] ed25519_dalek::SignatureError), } impl ResponseError for DtrfsError { diff --git a/dtrfs_api/src/os.rs b/dtrfs_api/src/os.rs index 3dcd1e3..3ca6e49 100644 --- a/dtrfs_api/src/os.rs +++ b/dtrfs_api/src/os.rs @@ -3,7 +3,7 @@ use base64::{ prelude::{Engine, BASE64_URL_SAFE}, DecodeError, }; -use derive_more::{Display, Error, From}; +use thiserror::Error; use std::{ fs::File, io::{self, BufRead, BufReader, Write}, @@ -12,31 +12,31 @@ use std::{ string::FromUtf8Error, }; -#[derive(Debug, Display, Error, From)] +#[derive(Debug, Error)] pub enum OsError { - #[display( + #[error( "OS installation script failed.\nScript stdout:\n{stdout}\nScript stderr:\n{stderr}" )] InstallationFailed { stdout: String, stderr: String }, - #[display("Could not decrypt disk.")] + #[error("Could not decrypt disk.")] DecryptionFailed, - #[display("Could not mount /dev/mapper/root to /mnt")] + #[error("Could not mount /dev/mapper/root to /mnt")] MountFailed, - #[display("Could not try hot keyfile: {_0}")] + #[error("Could not try hot keyfile: {0}")] TryHotKeyfileFailed(#[from] SNPError), - #[display("Could not replace hot keyfile using SNP KDF.")] + #[error("Could not replace hot keyfile using SNP KDF.")] ReplaceHotKeyfileFailed, - #[display("Operating system not mounted. Please install OS or decrypt existing OS.")] + #[error("Operating system not mounted. Please install OS or decrypt existing OS.")] OsNotMounted, - #[display("Supplied key is expected to have at least two words.")] + #[error("Supplied key is expected to have at least two words.")] InvalidSshKey, - #[display("authorized_keys already contains {err}")] + #[error("authorized_keys already contains {err}")] SshKeyAlreadyExists { err: String }, - #[display("I/O error: {_0}")] + #[error("I/O error: {0}")] IoError(#[from] io::Error), - #[display("Base64 decoding error: {_0}")] + #[error("Base64 decoding error: {0}")] Base64Error(#[from] DecodeError), - #[display("UTF-8 conversion error: {_0}")] + #[error("UTF-8 conversion error: {0}")] Utf8Error(#[from] FromUtf8Error), } diff --git a/dtrfs_api/src/snp.rs b/dtrfs_api/src/snp.rs index 5705f23..76878c6 100644 --- a/dtrfs_api/src/snp.rs +++ b/dtrfs_api/src/snp.rs @@ -1,17 +1,17 @@ use base64::prelude::{Engine, BASE64_URL_SAFE}; -use derive_more::{Display, Error, From}; +use thiserror::Error; use sev::error::UserApiError; use sev::firmware::guest::{AttestationReport, DerivedKey, Firmware, GuestFieldSelect}; -#[derive(Debug, Display, From, Error)] +#[derive(Debug, Error)] pub enum SNPError { - #[display("Could not parse the derived key: {_0}")] + #[error("Could not parse the derived key: {0}")] KeyParsingError(#[from] std::num::ParseIntError), - #[display("authorized_keys already contains: {_0}")] + #[error("authorized_keys already contains: {0}")] UserApiError(#[from] UserApiError), - #[display("I/O error: {_0}")] + #[error("I/O error: {0}")] FirmwareIOError(#[from] std::io::Error), - #[display("bincode Base64 decoding error: {_0}")] + #[error("bincode Base64 decoding error: {0}")] Base64Error(#[from] bincode::Error), } -- 2.43.0