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
use crate::alloc::borrow::ToOwned;
use crate::authenticated_storage::IdentityAttributeStorage;
use crate::credential::{Credential, CredentialData, Timestamp, Verified};
use crate::PublicIdentity;
use crate::{IdentityIdentifier, IdentityStateConst, IdentityVault};
use ockam_core::compat::collections::BTreeMap;
use ockam_core::compat::{string::String, sync::Arc, vec::Vec};
use ockam_core::errcode::{Kind, Origin};
use ockam_core::vault::Signature;
use ockam_core::{Error, Result};

impl PublicIdentity {
    /// Perform a signature check with the given identity.
    ///
    /// If successful, the credential data are returned.
    pub async fn verify_credential(
        &self,
        credential: &Credential,
        subject: &IdentityIdentifier,
        vault: Arc<dyn IdentityVault>,
    ) -> Result<CredentialData<Verified>> {
        let dat = CredentialData::try_from(credential)?;
        if dat.unverified_key_label() != IdentityStateConst::ROOT_LABEL {
            return Err(Error::new(
                Origin::Application,
                Kind::Invalid,
                "invalid signing key",
            ));
        }

        if &dat.issuer != self.identifier() {
            return Err(Error::new(
                Origin::Application,
                Kind::Invalid,
                "unknown authority",
            ));
        }

        if &dat.subject != subject {
            return Err(Error::new(
                Origin::Application,
                Kind::Invalid,
                "unknown subject",
            ));
        }

        let now = Timestamp::now()
            .ok_or_else(|| Error::new(Origin::Application, Kind::Invalid, "invalid system time"))?;
        if dat.expires <= now {
            return Err(Error::new(
                Origin::Application,
                Kind::Invalid,
                "expired credential",
            ));
        }

        let sig = Signature::new(credential.signature().to_vec());

        if !self
            .verify_signature(
                &sig,
                credential.unverified_data(),
                Some(dat.unverified_key_label()),
                vault,
            )
            .await?
        {
            return Err(Error::new(
                Origin::Application,
                Kind::Invalid,
                "invalid signature",
            ));
        }
        Ok(dat.into_verified())
    }

    /// Return authenticated non-expired attributes attached to that Identity
    pub async fn get_attributes(
        &self,
        authenticated_storage: &impl IdentityAttributeStorage,
    ) -> Result<Option<BTreeMap<String, Vec<u8>>>> {
        authenticated_storage
            .get_attributes(self.identifier())
            .await
            .map(|r| r.map(|e| e.attrs().to_owned()))
    }
}