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
124
125
126
127
// Copyright 2021 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0

use crate::{tss2_esys::TPMA_LOCALITY, Error, Result, WrapperErrorKind};
use bitfield::bitfield;
use log::error;

bitfield! {
    /// Bitfield representing the locality attributes.
    #[derive(Copy, Clone, Eq, PartialEq)]
    pub struct LocalityAttributes(TPMA_LOCALITY);
    impl Debug;

    _, set_locality_zero: 0;
    pub locality_zero, _: 0;
    _, set_locality_one: 1;
    pub locality_one, _: 1;
    _, set_locality_two: 2;
    pub locality_two, _: 2;
    _, set_locality_three: 3;
    pub locality_three, _: 3;
    _, set_locality_four: 4;
    pub locality_four, _: 4;
    _, set_extended: 7, 5;
    extended, _: 7, 5;
}

impl LocalityAttributes {
    pub const LOCALITY_ZERO: LocalityAttributes = LocalityAttributes(1);
    pub const LOCALITY_ONE: LocalityAttributes = LocalityAttributes(2);
    pub const LOCALITY_TWO: LocalityAttributes = LocalityAttributes(4);
    pub const LOCALITY_THREE: LocalityAttributes = LocalityAttributes(8);
    pub const LOCALITY_FOUR: LocalityAttributes = LocalityAttributes(16);
    /// Returns true if the attributes are extended
    pub fn is_extended(&self) -> bool {
        self.extended() != 0u8
    }

    /// Returns the LocalityAttributes as a number.
    ///
    /// # Errors
    /// If the attributes are not extended en InvalidParams error
    /// is returned.
    pub fn as_extended(&self) -> Result<u8> {
        if self.is_extended() {
            Ok(self.0)
        } else {
            error!("Cannot retrieve LocalityAttributes as extended when the attributes are not indicated to be extended");
            Err(Error::local_error(WrapperErrorKind::InvalidParam))
        }
    }

    /// Returns the builder used to construct LocalAttributes.
    pub const fn builder() -> LocalityAttributesBuilder {
        LocalityAttributesBuilder::new()
    }
}

impl From<TPMA_LOCALITY> for LocalityAttributes {
    fn from(tpma_locality: TPMA_LOCALITY) -> Self {
        LocalityAttributes(tpma_locality)
    }
}

impl From<LocalityAttributes> for TPMA_LOCALITY {
    fn from(locality_attributes: LocalityAttributes) -> Self {
        locality_attributes.0
    }
}

#[derive(Debug, Clone)]
pub struct LocalityAttributesBuilder {
    localities: Vec<u8>,
}

impl LocalityAttributesBuilder {
    /// Creates a new builder.
    pub const fn new() -> Self {
        LocalityAttributesBuilder {
            localities: Vec::new(),
        }
    }
    /// Adds a locality to the builder
    pub fn with_locality(mut self, locality: u8) -> Self {
        self.localities.push(locality);
        self
    }

    /// Adds a slice of localities to the builder
    pub fn with_localities(mut self, localities: &[u8]) -> Self {
        self.localities.extend_from_slice(localities);
        self
    }

    /// Builds the attributes
    pub fn build(self) -> Result<LocalityAttributes> {
        let mut locality_attributes = LocalityAttributes(0);
        for locality in self.localities {
            if locality_attributes.is_extended() {
                error!("Locality attribute {new} and locality attribute {prev} cannot be combined because locality attribute {prev} is extended", new=locality, prev=locality_attributes.0);
                return Err(Error::local_error(WrapperErrorKind::InvalidParam));
            }
            match locality {
                0 => locality_attributes.set_locality_zero(true),
                1 => locality_attributes.set_locality_one(true),
                2 => locality_attributes.set_locality_two(true),
                3 => locality_attributes.set_locality_three(true),
                4 => locality_attributes.set_locality_four(true),
                5..=31 => {
                    error!(
                        "Locality attribute {new} is invalid and cannot be combined with other locality attributes",
                        new=locality
                    );
                    return Err(Error::local_error(WrapperErrorKind::InvalidParam));
                }
                32..=255 => {
                    if locality_attributes.0 != 0 {
                        error!("Locality attribute {new} is extended and cannot be combined with locality attribute(s) {old}", new=locality, old=locality_attributes.0);
                        return Err(Error::local_error(WrapperErrorKind::InvalidParam));
                    }
                    locality_attributes.0 = locality;
                }
            }
        }
        Ok(locality_attributes)
    }
}