1use crate::error::{Result, ToolErrorKind};
7use log::{error, info};
8use parsec_client::core::interface::operations::psa_algorithm::{Algorithm, Hash, SignHash};
9use parsec_client::BasicClient;
10use picky_asn1::wrapper::IntegerAsn1;
11use serde::{Deserialize, Serialize};
12use sha2::digest::{Digest, DynDigest};
13
14#[derive(Serialize, Deserialize)]
15struct EccSignature {
16 r: IntegerAsn1,
17 s: IntegerAsn1,
18}
19
20pub fn sign_message_with_policy(
26 basic_client: &BasicClient,
27 key_name: &str,
28 msg: &[u8],
29 default_hash: Option<Hash>,
30) -> Result<Vec<u8>> {
31 let alg = basic_client
32 .key_attributes(key_name)?
33 .policy
34 .permitted_algorithms;
35
36 let signature = match alg {
37 Algorithm::AsymmetricSignature(alg) => {
38 let hash = match alg.hash() {
39 Some(SignHash::Specific(hash)) => hash_data(msg, hash)?,
40 Some(SignHash::Any) => {
41 if let Some(hash) = default_hash {
42 hash_data(msg, hash)?
43 } else {
44 error!("Signing key allows any hashing algorithm, but no default was specified.");
45 return Err(ToolErrorKind::NotSupported.into());
46 }
47 }
48 _ => {
49 error!("Asymmetric signing algorithm ({:?}) is not supported", alg);
50 return Err(ToolErrorKind::NotSupported.into());
51 }
52 };
53 info!("Signing data with {:?}...", alg);
54 let mut sig = basic_client.psa_sign_hash(key_name, &hash, alg)?;
55 if alg.is_ecc_alg() {
56 let s = IntegerAsn1::from_bytes_be_unsigned(sig.split_off(sig.len() / 2));
57 sig = picky_asn1_der::to_vec(&EccSignature {
58 r: IntegerAsn1::from_bytes_be_unsigned(sig),
59 s,
60 })
61 .unwrap();
62 }
63
64 sig
65 }
66 other => {
67 error!(
68 "Key's algorithm is {:?} which can not be used for signing.",
69 other
70 );
71 return Err(ToolErrorKind::WrongKeyAlgorithm.into());
72 }
73 };
74
75 Ok(signature)
76}
77
78fn hash_data(data: &[u8], alg: Hash) -> Result<Vec<u8>> {
79 let mut hasher: Box<dyn DynDigest> = match alg {
80 Hash::Sha224 => Box::from(sha2::Sha224::new()),
81 Hash::Sha256 => Box::from(sha2::Sha256::new()),
82 Hash::Sha384 => Box::from(sha2::Sha384::new()),
83 Hash::Sha512 => Box::from(sha2::Sha512::new()),
84 _ => {
85 error!("Hashing algorithm ({:?}) not supported", alg);
86 return Err(ToolErrorKind::NotSupported.into());
87 }
88 };
89 info!("Hashing data with {:?}...", alg);
90 hasher.update(data);
91 Ok(hasher.finalize().to_vec())
92}