parsec_interface/operations/
psa_verify_hash.rs

1// Copyright 2019 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3//! # PsaVerifyHash operation
4//!
5//! Verify the signature of a hash or short message using a public key.
6use super::psa_key_attributes::Attributes;
7use crate::operations::psa_algorithm::AsymmetricSignature;
8use crate::requests::ResponseStatus;
9
10/// Native object for asymmetric verification of signatures.
11#[derive(Debug)]
12pub struct Operation {
13    /// `key_name` specifies the key to be used for verification.
14    pub key_name: String,
15    /// An asymmetric signature algorithm that separates the hash and sign operations, that is
16    /// compatible with the type of key.
17    pub alg: AsymmetricSignature,
18    /// The `hash` contains a short message or hash value as described for the
19    /// asymmetric signing operation.
20    pub hash: zeroize::Zeroizing<Vec<u8>>,
21    /// Buffer containing the signature to verify.
22    pub signature: zeroize::Zeroizing<Vec<u8>>,
23}
24
25/// Native object for asymmetric verification of signatures.
26///
27/// The true result of the operation is sent as a `status` code in the response.
28#[derive(Copy, Clone, Debug)]
29pub struct Result;
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 verifying signatures on hashes
36    /// * the key policy allows the verification 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 verification algorithm
39    pub fn validate(&self, key_attributes: Attributes) -> crate::requests::Result<()> {
40        key_attributes.can_verify_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_verify_hash();
60        Attributes {
61            lifetime: Lifetime::Persistent,
62            key_type: Type::EccKeyPair {
63                curve_family: EccFamily::SecpR1,
64            },
65            bits: 256,
66            policy: Policy {
67                usage_flags,
68                permitted_algorithms: Algorithm::AsymmetricSignature(AsymmetricSignature::Ecdsa {
69                    hash_alg: Hash::Sha256.into(),
70                }),
71            },
72        }
73    }
74
75    #[test]
76    fn validate_success() {
77        (Operation {
78            key_name: String::from("some key"),
79            alg: AsymmetricSignature::Ecdsa {
80                hash_alg: Hash::Sha256.into(),
81            },
82            hash: vec![0xff; 32].into(),
83            signature: vec![0xa5; 65].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                signature: vec![0xa5; 65].into(),
101            })
102            .validate(attrs)
103            .unwrap_err(),
104            ResponseStatus::PsaErrorNotPermitted
105        );
106    }
107
108    #[test]
109    fn wrong_algorithm() {
110        assert_eq!(
111            (Operation {
112                key_name: String::from("some key"),
113                alg: AsymmetricSignature::Ecdsa {
114                    hash_alg: Hash::Sha224.into(),
115                },
116                hash: vec![0xff; 28].into(),
117                signature: vec![0xa5; 65].into(),
118            })
119            .validate(get_attrs())
120            .unwrap_err(),
121            ResponseStatus::PsaErrorNotPermitted
122        );
123    }
124
125    #[test]
126    fn wrong_scheme() {
127        assert_eq!(
128            (Operation {
129                key_name: String::from("some key"),
130                alg: AsymmetricSignature::RsaPss {
131                    hash_alg: Hash::Sha224.into(),
132                },
133                hash: vec![0xff; 28].into(),
134                signature: vec![0xa5; 65].into(),
135            })
136            .validate(get_attrs())
137            .unwrap_err(),
138            ResponseStatus::PsaErrorNotPermitted
139        );
140    }
141
142    #[test]
143    fn invalid_hash() {
144        assert_eq!(
145            (Operation {
146                key_name: String::from("some key"),
147                alg: AsymmetricSignature::Ecdsa {
148                    hash_alg: Hash::Sha256.into(),
149                },
150                hash: vec![0xff; 16].into(),
151                signature: vec![0xa5; 65].into(),
152            })
153            .validate(get_attrs())
154            .unwrap_err(),
155            ResponseStatus::PsaErrorInvalidArgument
156        );
157    }
158}