Files
sausage/host/src/cred/sign.rs
T

62 lines
1.8 KiB
Rust

//! Pure signing and public-key export over decrypted field values. No storage or grant policy.
use super::keys;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Error {
pub kind: &'static str,
pub message: &'static str,
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.message)
}
}
impl std::error::Error for Error {}
pub type Result<T> = std::result::Result<T, Error>;
pub(super) fn error(kind: &'static str, message: &'static str) -> Error {
Error { kind, message }
}
pub(super) fn invalid_key() -> Error {
error("invalid_key", "invalid signing key encoding or length")
}
#[derive(Debug, serde::Serialize)]
pub struct SignResult {
pub signature: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub bytes: Option<Vec<u8>>,
}
/// Sign bytes. RSA requires explicit, matching padding and digest parameters.
pub fn sign(
value: &str,
passphrase: Option<&str>,
format: &str,
payload: &[u8],
output: &str,
padding: Option<&str>,
hash: Option<&str>,
) -> Result<SignResult> {
keys::check(format, padding, hash)?;
let key = keys::read(value, format, passphrase)?;
keys::output(format, output, keys::sign_key(&key, format, payload)?)
}
/// Export only the public part of an asymmetric key.
pub fn public_key(
value: &str,
passphrase: Option<&str>,
format: &str,
output: &str,
) -> Result<String> {
keys::public(&keys::read(value, format, passphrase)?, output)
}
/// Generate a P-256 private key in PKCS#8 PEM format for ES256.
pub fn generate_es256() -> Result<zeroize::Zeroizing<String>> {
use p256::pkcs8::EncodePrivateKey;
p256::SecretKey::random(&mut rsa::rand_core::OsRng)
.to_pkcs8_pem(Default::default())
.map_err(|_| invalid_key())
}