parsec_interface/operations/
psa_sign_hash.rs

1// Copyright 2019 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3//! # PsaSignHash operation
4//!
5//! Sign an already-calculated hash with a private key.
6
7use super::psa_key_attributes::Attributes;
8use crate::operations::psa_algorithm::AsymmetricSignature;
9use crate::requests::ResponseStatus;
10
11/// Native object for asymmetric sign operations.
12#[derive(Debug)]
13pub struct Operation {
14    /// Defines which key should be used for the signing operation.
15    pub key_name: String,
16    /// An asymmetric signature algorithm that separates the hash and sign operations, that is
17    /// compatible with the type of key.
18    pub alg: AsymmetricSignature,
19    /// The input whose signature is to be verified. This is usually the hash of a message.
20    pub hash: zeroize::Zeroizing<Vec<u8>>,
21}
22
23/// Native object for asymmetric sign result.
24#[derive(Debug)]
25pub struct Result {
26    /// The `signature` field contains the resulting bytes from the signing operation. The format of
27    /// the signature is as specified by the provider doing the signing.
28    pub signature: zeroize::Zeroizing<Vec<u8>>,
29}
30
31impl Operation {
32    /// Validate the contents of the operation against the attributes of the key it targets
33    ///
34    /// This method checks that:
35    /// * the key policy allows signing hashes
36    /// * the key policy allows the signing algorithm requested in the operation
37    /// * the key type is compatible with the requested algorithm
38    /// * the length of the given digest is consistent with the specified signing algorithm
39    pub fn validate(&self, key_attributes: Attributes) -> crate::requests::Result<()> {
40        key_attributes.can_sign_hash()?;
41        key_attributes.permits_alg(self.alg.into())?;
42        key_attributes.compatible_with_alg(self.alg.into())?;
43        if !self.alg.is_hash_len_permitted(self.hash.len()) {
44            return Err(ResponseStatus::PsaErrorInvalidArgument);
45        }
46
47        Ok(())
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54    use crate::operations::psa_algorithm::{Algorithm, AsymmetricSignature, Hash};
55    use crate::operations::psa_key_attributes::{EccFamily, Lifetime, Policy, Type, UsageFlags};
56
57    fn get_attrs() -> Attributes {
58        let mut usage_flags = UsageFlags::default();
59        let _ = usage_flags.set_sign_hash();
60
61        Attributes {
62            lifetime: Lifetime::Persistent,
63            key_type: Type::EccKeyPair {
64                curve_family: EccFamily::SecpR1,
65            },
66            bits: 256,
67            policy: Policy {
68                usage_flags,
69                permitted_algorithms: Algorithm::AsymmetricSignature(AsymmetricSignature::Ecdsa {
70                    hash_alg: Hash::Sha256.into(),
71                }),
72            },
73        }
74    }
75
76    #[test]
77    fn validate_success() {
78        (Operation {
79            key_name: String::from("some key"),
80            alg: AsymmetricSignature::Ecdsa {
81                hash_alg: Hash::Sha256.into(),
82            },
83            hash: vec![0xff; 32].into(),
84        })
85        .validate(get_attrs())
86        .unwrap();
87    }
88
89    #[test]
90    fn cannot_sign() {
91        let mut attrs = get_attrs();
92        attrs.policy.usage_flags = UsageFlags::default();
93        assert_eq!(
94            (Operation {
95                key_name: String::from("some key"),
96                alg: AsymmetricSignature::Ecdsa {
97                    hash_alg: Hash::Sha256.into(),
98                },
99                hash: vec![0xff; 32].into(),
100            })
101            .validate(attrs)
102            .unwrap_err(),
103            ResponseStatus::PsaErrorNotPermitted
104        );
105    }
106
107    #[test]
108    fn wrong_algorithm() {
109        assert_eq!(
110            (Operation {
111                key_name: String::from("some key"),
112                alg: AsymmetricSignature::Ecdsa {
113                    hash_alg: Hash::Sha224.into(),
114                },
115                hash: vec![0xff; 28].into(),
116            })
117            .validate(get_attrs())
118            .unwrap_err(),
119            ResponseStatus::PsaErrorNotPermitted
120        );
121    }
122
123    #[test]
124    fn wrong_scheme() {
125        assert_eq!(
126            (Operation {
127                key_name: String::from("some key"),
128                alg: AsymmetricSignature::RsaPss {
129                    hash_alg: Hash::Sha224.into(),
130                },
131                hash: vec![0xff; 28].into(),
132            })
133            .validate(get_attrs())
134            .unwrap_err(),
135            ResponseStatus::PsaErrorNotPermitted
136        );
137    }
138
139    #[test]
140    fn invalid_hash() {
141        assert_eq!(
142            (Operation {
143                key_name: String::from("some key"),
144                alg: AsymmetricSignature::Ecdsa {
145                    hash_alg: Hash::Sha256.into(),
146                },
147                hash: vec![0xff; 16].into(),
148            })
149            .validate(get_attrs())
150            .unwrap_err(),
151            ResponseStatus::PsaErrorInvalidArgument
152        );
153    }
154}