mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
rust/pvsecret: Add support for retrievable secrets
Support for creating and retrieving retrievable secrets. Acked-by: Marc Hartmayer <marc@linux.ibm.com> Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com> Signed-off-by: Steffen Eiden <seiden@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
committed by
Jan Höppner
parent
a14f9d4edc
commit
93da795520
@@ -4,7 +4,6 @@
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
use crate::cli::{AddSecretType, CreateSecretFlags, CreateSecretOpt};
|
||||
use anyhow::{anyhow, bail, Context, Error, Result};
|
||||
use log::{debug, info, trace, warn};
|
||||
use pv::{
|
||||
@@ -22,6 +21,8 @@ use pv::{
|
||||
use serde_yaml::Value;
|
||||
use utils::get_writer_from_cli_file_arg;
|
||||
|
||||
use crate::cli::{AddSecretType, CreateSecretFlags, CreateSecretOpt, RetrieveableSecretInpKind};
|
||||
|
||||
fn write_out<P, D>(path: &P, data: D, ctx: &str) -> pv::Result<()>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
@@ -32,6 +33,23 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn retrievable(name: &str, secret: &str, kind: &RetrieveableSecretInpKind) -> Result<GuestSecret> {
|
||||
let secret_data = read_file(secret, &format!("retrievable {kind}"))?.into();
|
||||
|
||||
match kind {
|
||||
RetrieveableSecretInpKind::Plain => GuestSecret::plaintext(name, secret_data),
|
||||
RetrieveableSecretInpKind::Aes => GuestSecret::aes(name, secret_data),
|
||||
RetrieveableSecretInpKind::AesXts => GuestSecret::aes_xts(name, secret_data),
|
||||
RetrieveableSecretInpKind::HmacSha => GuestSecret::hmac_sha(name, secret_data),
|
||||
RetrieveableSecretInpKind::Ec => GuestSecret::ec(
|
||||
name,
|
||||
read_private_key(secret_data.value())
|
||||
.with_context(|| format!("Cannot read {secret} as {kind} from PEM or DER"))?,
|
||||
),
|
||||
}
|
||||
.map_err(Error::from)
|
||||
}
|
||||
|
||||
/// Prepare an add-secret request
|
||||
pub fn create(opt: &CreateSecretOpt) -> Result<()> {
|
||||
if pv_guest_bit_set() {
|
||||
@@ -88,6 +106,9 @@ fn build_asrcb(opt: &CreateSecretOpt) -> Result<AddSecretRequest> {
|
||||
input_secret: None,
|
||||
..
|
||||
} => GuestSecret::association(name, None)?,
|
||||
AddSecretType::Retrievable {
|
||||
name, secret, kind, ..
|
||||
} => retrievable(name, secret, kind)?,
|
||||
};
|
||||
trace!("AddSecret: {secret:x?}");
|
||||
|
||||
@@ -136,7 +157,9 @@ fn build_asrcb(opt: &CreateSecretOpt) -> Result<AddSecretRequest> {
|
||||
.as_ref()
|
||||
.map(|p| read_file(p, "User-signing key"))
|
||||
.transpose()?
|
||||
.map(|buf| read_private_key(&buf))
|
||||
.map(|buf| {
|
||||
read_private_key(&buf).context("Cannot read {secret} as private key from PEM or DER")
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
if user_data.is_some() || user_key.is_some() {
|
||||
@@ -258,6 +281,9 @@ fn write_secret<P: AsRef<Path>>(
|
||||
write_out(path, guest_secret.confidential(), "Association secret")?
|
||||
}
|
||||
}
|
||||
AddSecretType::Retrievable { name, stdout, .. } => {
|
||||
write_yaml(name, guest_secret, stdout, outp_path)?
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
Ok(())
|
||||
|
||||
@@ -3,21 +3,25 @@
|
||||
// Copyright IBM Corp. 2023
|
||||
|
||||
use crate::cli::{ListSecretOpt, ListSecretOutputType};
|
||||
use anyhow::{Context, Result};
|
||||
use anyhow::{Context, Error, Result};
|
||||
use log::warn;
|
||||
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<()> {
|
||||
let uv = UvDevice::open()?;
|
||||
pub fn list_uvc(uv: &UvDevice) -> Result<SecretList> {
|
||||
let mut cmd = ListCmd::default();
|
||||
match uv.send_cmd(&mut cmd)? {
|
||||
UvcSuccess::RC_SUCCESS => (),
|
||||
UvcSuccess::RC_MORE_DATA => warn!("There is more data available than expected"),
|
||||
};
|
||||
cmd.try_into().map_err(Error::new)
|
||||
}
|
||||
|
||||
let secret_list: SecretList = cmd.try_into()?;
|
||||
/// Do a List Secrets UVC and output the list in the requested format
|
||||
pub fn list(opt: &ListSecretOpt) -> Result<()> {
|
||||
let uv = UvDevice::open()?;
|
||||
let secret_list = list_uvc(&uv)?;
|
||||
let mut wr_out = get_writer_from_cli_file_arg(&opt.output)?;
|
||||
|
||||
match &opt.format {
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// Copyright IBM Corp. 2024
|
||||
|
||||
use super::list::list_uvc;
|
||||
use crate::cli::{RetrInpFmt, RetrOutFmt, RetrSecretOptions};
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use log::{debug, info};
|
||||
use pv::{
|
||||
misc::open_file,
|
||||
misc::write,
|
||||
secret::{GuestSecret, RetrievedSecret},
|
||||
uv::{RetrieveCmd, SecretId, UvDevice},
|
||||
};
|
||||
use utils::get_writer_from_cli_file_arg;
|
||||
|
||||
fn retrieve(id: &SecretId) -> Result<RetrievedSecret> {
|
||||
let uv = UvDevice::open()?;
|
||||
let secrets = list_uvc(&uv)?;
|
||||
let secret = secrets
|
||||
.into_iter()
|
||||
.find(|s| s.id() == id.as_ref())
|
||||
.ok_or(anyhow!(
|
||||
"The UV secret-store has no secret with the ID {id}"
|
||||
))?;
|
||||
|
||||
info!("Try to retrieve secret at index: {}", secret.index());
|
||||
debug!("Try to retrieve: {secret:?}");
|
||||
|
||||
let mut uv_cmd = RetrieveCmd::from_entry(secret)?;
|
||||
uv.send_cmd(&mut uv_cmd)?;
|
||||
|
||||
Ok(RetrievedSecret::from_cmd(uv_cmd))
|
||||
}
|
||||
|
||||
pub fn retr(opt: &RetrSecretOptions) -> Result<()> {
|
||||
let mut output = get_writer_from_cli_file_arg(&opt.output)?;
|
||||
let id = match &opt.inform {
|
||||
RetrInpFmt::Yaml => match serde_yaml::from_reader(&mut open_file(&opt.input)?)? {
|
||||
GuestSecret::Retrievable { id, .. } => id,
|
||||
gs => bail!("The file contains a {gs}-secret, which is not retrievable."),
|
||||
},
|
||||
RetrInpFmt::Hex => {
|
||||
serde_yaml::from_str(&opt.input).context("Cannot parse SecretId information")?
|
||||
}
|
||||
};
|
||||
|
||||
let retr_secret =
|
||||
retrieve(&id).context("Could not retrieve the secret from the UV secret store.")?;
|
||||
|
||||
let out_data = match opt.outform {
|
||||
RetrOutFmt::Bin => retr_secret.into_bytes(),
|
||||
RetrOutFmt::Pem => retr_secret.to_pem()?.into_bytes(),
|
||||
};
|
||||
write(
|
||||
&mut output,
|
||||
out_data.value(),
|
||||
&opt.output,
|
||||
"IBM Protected Key",
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user