mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
rust: Refactoring and reduce API surface
Prepare pv & pv_core crates to be released on crates.io: * Remove any unused API to stay flexible * Remove utils dependency * Move cli, tmpfile and version utilities to local utils crate * Use the new utilities in the pv tools * Rename Secret into Confidential to avoid confusion of Secret (now Confidential) and AddSecret requests. * Move the uvsecret module out of the request module and change the name to secret. * Cleanup dependencies * Precise and correct minimal dependency versions * Inline `Aes256Key::from_digest` The cleanup ensures that the code also compiles with the dependencies resolved to their minimal versions using: $ cargo +nightly -Z minimal-versions update $ cargo build For more information refer to this blog post: https://users.rust-lang.org/t/psa-please-specify-precise-dependency-versions-in-cargo-toml/71277/8 Signed-off-by: Marc Hartmayer <mhartmay@de.ibm.com> Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
This commit is contained in:
@@ -3,8 +3,7 @@
|
||||
// Copyright IBM Corp. 2023
|
||||
|
||||
use clap::{ArgGroup, Args, CommandFactory, Parser, Subcommand, ValueEnum, ValueHint};
|
||||
use pv::misc::CertificateOptions;
|
||||
use pv::misc::STDOUT;
|
||||
use utils::{CertificateOptions, STDOUT};
|
||||
|
||||
/// Manage secrets for IBM Secure Execution guests.
|
||||
///
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
use crate::cli::AddSecretOpt;
|
||||
use anyhow::{Context, Result};
|
||||
use log::warn;
|
||||
use pv::misc::get_reader_from_cli_file_arg;
|
||||
use pv::uv::{AddCmd, UvDevice};
|
||||
use utils::get_reader_from_cli_file_arg;
|
||||
|
||||
/// Do an Add Secret UVC
|
||||
pub fn add(opt: &AddSecretOpt) -> Result<()> {
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp. 2023
|
||||
// Copyright IBM Corp. 2023, 2024
|
||||
|
||||
use crate::cli::{AddSecretType, CreateSecretFlags, CreateSecretOpt};
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use anyhow::{anyhow, bail, Context, Error, Result};
|
||||
use log::{debug, info, trace, warn};
|
||||
use pv::{
|
||||
misc::{
|
||||
get_writer_from_cli_file_arg, open_file, parse_hex, pv_guest_bit_set, read_certs,
|
||||
read_exact_file, read_file, read_private_key, try_parse_u128, try_parse_u64, write,
|
||||
open_file, parse_hex, pv_guest_bit_set, read_exact_file, read_file, try_parse_u128,
|
||||
try_parse_u64, write,
|
||||
},
|
||||
request::{
|
||||
openssl::pkey::{PKey, Public},
|
||||
uvsecret::{AddSecretFlags, AddSecretRequest, AddSecretVersion, ExtSecret, GuestSecret},
|
||||
BootHdrTags, HkdVerifier, ReqEncrCtx, Request, SymKeyType,
|
||||
openssl::pkey::{PKey, Private},
|
||||
BootHdrTags, ReqEncrCtx, Request, SymKeyType,
|
||||
},
|
||||
secret::{AddSecretFlags, AddSecretRequest, AddSecretVersion, ExtSecret, GuestSecret},
|
||||
uv::ConfigUid,
|
||||
};
|
||||
use serde_yaml::Value;
|
||||
use utils::get_writer_from_cli_file_arg;
|
||||
|
||||
fn write_out<D: AsRef<[u8]>>(path: &str, data: D, ctx: &str) -> pv::Result<()> {
|
||||
let mut wr = get_writer_from_cli_file_arg(path)?;
|
||||
@@ -40,8 +41,8 @@ pub fn create(opt: &CreateSecretOpt) -> Result<()> {
|
||||
debug!("Generated Add-secret request");
|
||||
|
||||
// Add host-key documents
|
||||
let verifier = opt.certificate_args.verifier()?;
|
||||
read_and_verify_hkds(&opt.certificate_args.host_key_documents, verifier)?
|
||||
opt.certificate_args
|
||||
.get_verified_hkds("secret")?
|
||||
.into_iter()
|
||||
.for_each(|k| asrcb.add_hostkey(k));
|
||||
|
||||
@@ -57,6 +58,13 @@ pub fn create(opt: &CreateSecretOpt) -> Result<()> {
|
||||
write_secret(&opt.secret, &asrcb)
|
||||
}
|
||||
|
||||
/// Read+parse the first key from the buffer.
|
||||
fn read_private_key(buf: &[u8]) -> Result<PKey<Private>> {
|
||||
PKey::private_key_from_der(buf)
|
||||
.or_else(|_| PKey::private_key_from_pem(buf))
|
||||
.map_err(Error::new)
|
||||
}
|
||||
|
||||
/// Set-up the `add-secret request` from command-line arguments
|
||||
fn build_asrcb(opt: &CreateSecretOpt) -> Result<AddSecretRequest> {
|
||||
debug!("Build add-secret request");
|
||||
@@ -191,38 +199,6 @@ fn read_cuid(asrcb: &mut AddSecretRequest, opt: &CreateSecretOpt) -> Result<()>
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// reads HKDs into memory, verifies them with the provided HKD verifier.
|
||||
/// returns list of public keys or Err
|
||||
/// Aborts on first error
|
||||
fn read_and_verify_hkds(
|
||||
hkds: &Vec<String>,
|
||||
verifier: Box<dyn HkdVerifier>,
|
||||
) -> Result<Vec<PKey<Public>>> {
|
||||
let mut res = Vec::with_capacity(hkds.len());
|
||||
for hkd in hkds {
|
||||
let hk = read_file(hkd, "host-key document")?;
|
||||
let certs = read_certs(&hk).with_context(|| {
|
||||
format!("The provided Host Key Document in '{hkd}' is not in PEM or DER format")
|
||||
})?;
|
||||
if certs.is_empty() {
|
||||
let msg = format!(
|
||||
"The provided host key document in {} contains no certificate!",
|
||||
hkd
|
||||
);
|
||||
return Err(anyhow!(msg));
|
||||
}
|
||||
if certs.len() > 1 {
|
||||
warn!("The host key document in '{hkd}' contains more than one certificate! Only the first certificate will be used.")
|
||||
}
|
||||
|
||||
// len is >= 1 -> unwrap will succeed
|
||||
let c = certs.first().unwrap();
|
||||
verifier.verify(c)?;
|
||||
res.push(c.public_key()?);
|
||||
info!("Use host-key document at '{hkd}'");
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
/// Write the generated secret (if any) to the specified output stream
|
||||
fn write_secret(secret: &AddSecretType, asrcb: &AddSecretRequest) -> Result<()> {
|
||||
if let AddSecretType::Association {
|
||||
@@ -262,3 +238,21 @@ fn write_secret(secret: &AddSecretType, asrcb: &AddSecretRequest) -> Result<()>
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
#[test]
|
||||
fn read_private_key() {
|
||||
let key = include_bytes!("../../../pv/tests/assets/keys/rsa3072key.pem");
|
||||
let key = super::read_private_key(key).unwrap();
|
||||
assert_eq!(key.rsa().unwrap().size(), 384);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_private_key_fail() {
|
||||
let key = include_bytes!("create.rs");
|
||||
let key = super::read_private_key(key);
|
||||
assert!(key.is_err());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
use crate::cli::{ListSecretOpt, ListSecretOutputType};
|
||||
use anyhow::{Context, Result};
|
||||
use log::warn;
|
||||
use pv::{
|
||||
misc::{get_writer_from_cli_file_arg, STDOUT},
|
||||
uv::{ListCmd, SecretList, UvDevice, UvcSuccess},
|
||||
};
|
||||
use pv::uv::{ListCmd, SecretList, UvDevice, UvcSuccess};
|
||||
use utils::{get_writer_from_cli_file_arg, STDOUT};
|
||||
|
||||
/// Do a List Secrets UVC
|
||||
pub fn list(opt: &ListSecretOpt) -> Result<()> {
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
use crate::cli::VerifyOpt;
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use log::warn;
|
||||
use pv::misc::{read_certs, read_file};
|
||||
use pv::{
|
||||
misc::{get_reader_from_cli_file_arg, get_writer_from_cli_file_arg, read_certs, read_file},
|
||||
request::{
|
||||
openssl::pkey::{PKey, Public},
|
||||
uvsecret::verify_asrcb_and_get_user_data,
|
||||
},
|
||||
request::openssl::pkey::{PKey, Public},
|
||||
secret::verify_asrcb_and_get_user_data,
|
||||
};
|
||||
|
||||
use crate::cli::VerifyOpt;
|
||||
use utils::{get_reader_from_cli_file_arg, get_writer_from_cli_file_arg};
|
||||
|
||||
/// read the content of a DER or PEM x509 and return the public key
|
||||
fn read_sgn_key(path: &str) -> Result<PKey<Public>> {
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp. 2023
|
||||
// Copyright IBM Corp. 2023, 2024
|
||||
|
||||
mod cli;
|
||||
mod cmd;
|
||||
|
||||
use clap::CommandFactory;
|
||||
use clap::Parser;
|
||||
use clap::{CommandFactory, Parser};
|
||||
use cli::{CliOptions, Command};
|
||||
use log::trace;
|
||||
use pv::misc::PvLogger;
|
||||
use std::process::ExitCode;
|
||||
use utils::release_string;
|
||||
use utils::{print_cli_error, print_error, print_version, PvLogger};
|
||||
|
||||
use crate::cli::validate_cli;
|
||||
|
||||
@@ -19,44 +17,8 @@ static LOGGER: PvLogger = PvLogger;
|
||||
static EXIT_LOGGER: u8 = 3;
|
||||
const FEATURES: &[&[&str]] = &[cmd::CMD_FN, cmd::UV_CMD_FN];
|
||||
|
||||
fn print_error(e: anyhow::Error, verbosity: u8) -> ExitCode {
|
||||
if verbosity > 0 {
|
||||
// Debug formatter also prints the whole error stack
|
||||
// So only print it when on verbose
|
||||
eprintln!("error: {e:?}")
|
||||
} else {
|
||||
eprintln!("error: {e}")
|
||||
};
|
||||
ExitCode::FAILURE
|
||||
}
|
||||
|
||||
fn print_cli_error(e: clap::Error) -> ExitCode {
|
||||
let ret = if e.use_stderr() {
|
||||
ExitCode::FAILURE
|
||||
} else {
|
||||
ExitCode::SUCCESS
|
||||
};
|
||||
//Ignore any errors during printing of the error
|
||||
let _ = e.format(&mut CliOptions::command()).print();
|
||||
ret
|
||||
}
|
||||
|
||||
fn print_version(verbosity: u8) -> anyhow::Result<()> {
|
||||
println!(
|
||||
"{} version {}\nCopyright IBM Corp. 2023",
|
||||
env!("CARGO_PKG_NAME"),
|
||||
release_string!()
|
||||
);
|
||||
if verbosity > 0 {
|
||||
FEATURES.concat().iter().for_each(|f| print!("{f} "));
|
||||
println!("(compiled)");
|
||||
println!(
|
||||
"\n{}-crate {}",
|
||||
env!("CARGO_PKG_NAME"),
|
||||
env!("CARGO_PKG_VERSION")
|
||||
);
|
||||
println!("{}", pv::crate_info());
|
||||
}
|
||||
print_version!(verbosity, "2024", FEATURES.concat());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -64,9 +26,9 @@ fn main() -> ExitCode {
|
||||
let cli: CliOptions = match CliOptions::try_parse() {
|
||||
Ok(cli) => match validate_cli(&cli) {
|
||||
Ok(_) => cli,
|
||||
Err(e) => return print_cli_error(e),
|
||||
Err(e) => return print_cli_error(e, CliOptions::command()),
|
||||
},
|
||||
Err(e) => return print_cli_error(e),
|
||||
Err(e) => return print_cli_error(e, CliOptions::command()),
|
||||
};
|
||||
|
||||
// set up logger/std(out,err)
|
||||
@@ -97,6 +59,6 @@ fn main() -> ExitCode {
|
||||
|
||||
match res {
|
||||
Ok(_) => ExitCode::SUCCESS,
|
||||
Err(e) => print_error(e, cli.verbose),
|
||||
Err(e) => print_error(&e, cli.verbose),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user