1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0
//! # PsaRawKeyAgreement operation
//!
//! Perform a raw key agreement.

use super::psa_key_attributes::Attributes;
use crate::operations::psa_algorithm::{KeyAgreement, RawKeyAgreement};
use derivative::Derivative;

/// Native object for raw key agreement operation.
#[derive(Derivative)]
#[derivative(Debug)]
pub struct Operation {
    /// `alg` specifies the raw key agreement algorithm to use. It must allow the `derive` usage flag.
    pub alg: RawKeyAgreement,
    /// `private_key_name` specifies a name of the private key to use in the key agreement operation.
    pub private_key_name: String,
    /// `peer_key` contains the bytes of a peers public key, to be used in the key agreement operation.
    /// This must be in the format that `PsaImportKey` accepts.
    #[derivative(Debug = "ignore")]
    pub peer_key: zeroize::Zeroizing<Vec<u8>>,
}

/// Native object for result for raw key agreement operation.
#[derive(Derivative)]
#[derivative(Debug)]
pub struct Result {
    /// `data` holds the bytes defining the key, formatted as specified
    /// by the provider for which the request was made.
    #[derivative(Debug = "ignore")]
    pub shared_secret: crate::secrecy::Secret<Vec<u8>>,
}

impl Operation {
    /// Validate the contents of the operation against the attributes of the key it targets
    ///
    /// This method checks that:
    /// * the key policy allows derivation
    /// * the key policy allows the key agreement algorithm requested in the operation
    /// * the key type is compatible with the requested algorithm
    pub fn validate(&self, key_attributes: Attributes) -> crate::requests::Result<()> {
        key_attributes.can_derive_from()?;
        key_attributes.permits_alg(KeyAgreement::Raw(self.alg).into())?;
        key_attributes.compatible_with_alg(KeyAgreement::Raw(self.alg).into())?;

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::operations::psa_algorithm::{KeyAgreement, RawKeyAgreement};
    use crate::operations::psa_key_attributes::{EccFamily, Lifetime, Policy, Type, UsageFlags};
    use crate::requests::ResponseStatus;

    fn get_attrs() -> Attributes {
        Attributes {
            lifetime: Lifetime::Persistent,
            key_type: Type::EccKeyPair {
                curve_family: EccFamily::SecpR1,
            },
            bits: 256,
            policy: Policy {
                usage_flags: UsageFlags {
                    export: false,
                    copy: false,
                    cache: false,
                    encrypt: false,
                    decrypt: false,
                    sign_message: false,
                    verify_message: false,
                    sign_hash: false,
                    verify_hash: false,
                    derive: true,
                },
                permitted_algorithms: KeyAgreement::Raw(RawKeyAgreement::Ecdh).into(),
            },
        }
    }

    #[test]
    fn validate_success() {
        (Operation {
            private_key_name: String::from("some key"),
            alg: RawKeyAgreement::Ecdh,
            peer_key: vec![0xff, 32].into(),
        })
        .validate(get_attrs())
        .unwrap();
    }

    #[test]
    fn cannot_derive() {
        let mut attrs = get_attrs();
        attrs.policy.usage_flags.derive = false;
        assert_eq!(
            (Operation {
                private_key_name: String::from("some key"),
                alg: RawKeyAgreement::Ecdh,
                peer_key: vec![0xff, 32].into(),
            })
            .validate(attrs)
            .unwrap_err(),
            ResponseStatus::PsaErrorNotPermitted
        );
    }

    #[test]
    fn wrong_algorithm() {
        assert_eq!(
            (Operation {
                private_key_name: String::from("some key"),
                alg: RawKeyAgreement::Ffdh,
                peer_key: vec![0xff, 32].into(),
            })
            .validate(get_attrs())
            .unwrap_err(),
            ResponseStatus::PsaErrorNotPermitted
        );
    }
}