ssi_vc/v1/data_model/
credential.rs

1use iref::{Iri, Uri};
2use ssi_claims_core::{ClaimsValidity, DateTimeProvider, InvalidClaims, VerifiableClaims};
3use ssi_data_integrity::{CryptographicSuite, DataIntegrity};
4use static_iref::iri;
5use xsd_types::DateTime;
6
7use crate::{v1::syntax::VERIFIABLE_CREDENTIAL_TYPE, Identified, MaybeIdentified, Typed};
8
9pub const VERIFIABLE_CREDENTIAL: &Iri =
10    iri!("https://www.w3.org/2018/credentials#VerifiableCredential");
11
12/// Credential trait.
13pub trait Credential {
14    /// Credential subject type.
15    type Subject;
16
17    /// Issuer type.
18    type Issuer: ?Sized + Identified;
19
20    /// Credential status type.
21    type Status: Identified + Typed;
22
23    /// Refresh service.
24    ///
25    /// See: <https://www.w3.org/TR/vc-data-model//#refreshing>
26    type RefreshService: Identified + Typed;
27
28    /// Terms of Use type.
29    ///
30    /// Terms of use can be utilized by an issuer or a holder to communicate the
31    /// terms under which a verifiable credential or verifiable presentation was
32    /// issued.
33    type TermsOfUse: MaybeIdentified + Typed;
34
35    /// Evidence type.
36    ///
37    /// Can be included by an issuer to provide the verifier with additional
38    /// supporting information in a verifiable credential.
39    type Evidence: MaybeIdentified + Typed;
40
41    /// Credential Schemas (Zero-Knowledge Proofs).
42    ///
43    /// See: <https://www.w3.org/TR/vc-data-model//#zero-knowledge-proofs>
44    type Schema: Identified + Typed;
45
46    /// Identifier.
47    fn id(&self) -> Option<&Uri> {
48        None
49    }
50
51    /// Types that are **not** `VerifiableCredential`.
52    ///
53    /// Since the `VerifiableCredential` type is *required*, it is omitted from
54    /// the value returned by this function. If you need to iterate over
55    /// all the credential types, including `VerifiableCredential`, use the
56    /// [`Self::types`] method.
57    fn additional_types(&self) -> &[String] {
58        &[]
59    }
60
61    fn types(&self) -> CredentialTypes {
62        CredentialTypes::from_additional_types(self.additional_types())
63    }
64
65    /// Credential subject.
66    fn credential_subjects(&self) -> &[Self::Subject] {
67        &[]
68    }
69
70    /// Issuer.
71    ///
72    /// This property is *required* for the credential to be *verifiable*.
73    fn issuer(&self) -> &Self::Issuer;
74
75    /// Issuance date.
76    ///
77    /// This property is *required* for the credential to be *verifiable*.
78    fn issuance_date(&self) -> Option<DateTime>;
79
80    /// Expiration date.
81    fn expiration_date(&self) -> Option<DateTime> {
82        None
83    }
84
85    /// Credential status.
86    ///
87    /// Used for discovery of information about the current status of a
88    /// verifiable credential, such as whether it is suspended or revoked.
89    fn credential_status(&self) -> &[Self::Status] {
90        &[]
91    }
92
93    /// Refresh services.
94    ///
95    /// See: <https://www.w3.org/TR/vc-data-model//#refreshing>
96    fn refresh_services(&self) -> &[Self::RefreshService] {
97        &[]
98    }
99
100    /// Terms of Use.
101    ///
102    /// Terms of use can be utilized by an issuer or a holder to communicate the
103    /// terms under which a verifiable credential or verifiable presentation was
104    /// issued.
105    fn terms_of_use(&self) -> &[Self::TermsOfUse] {
106        &[]
107    }
108
109    /// Evidence.
110    ///
111    /// Can be included by an issuer to provide the verifier with additional
112    /// supporting information in a verifiable credential.
113    fn evidence(&self) -> &[Self::Evidence] {
114        &[]
115    }
116
117    /// Credential Schemas (Zero-Knowledge Proofs).
118    ///
119    /// See: <https://www.w3.org/TR/vc-data-model//#zero-knowledge-proofs>
120    fn credential_schemas(&self) -> &[Self::Schema] {
121        &[]
122    }
123
124    /// Validates the credential.
125    ///
126    /// Validation consists in verifying that the claims themselves are
127    /// consistent and valid with regard to the verification environment.
128    /// For instance, checking that a credential's expiration date is not in the
129    /// past, or the issue date not in the future.
130    ///
131    /// Validation may fail even if the credential proof is successfully
132    /// verified.
133    fn validate_credential<E>(&self, env: &E) -> ClaimsValidity
134    where
135        E: DateTimeProvider,
136    {
137        let now = env.date_time();
138
139        let issuance_date = self
140            .issuance_date()
141            .ok_or(InvalidClaims::MissingIssuanceDate)?;
142
143        let valid_from = issuance_date.earliest().to_utc();
144        if valid_from > now {
145            // Credential is issued in the future!
146            return Err(InvalidClaims::Premature { now, valid_from });
147        }
148
149        if let Some(t) = self.expiration_date() {
150            let valid_until = t.latest().to_utc();
151            if now >= valid_until {
152                // Credential has expired.
153                return Err(InvalidClaims::Expired { now, valid_until });
154            }
155        }
156
157        Ok(())
158    }
159}
160
161pub trait VerifiableCredential: Credential + VerifiableClaims {}
162
163impl<T: Credential + VerifiableClaims> VerifiableCredential for T {}
164
165impl<T: Credential, S: CryptographicSuite> Credential for DataIntegrity<T, S> {
166    type Subject = T::Subject;
167    type Issuer = T::Issuer;
168    type Status = T::Status;
169    type RefreshService = T::RefreshService;
170    type TermsOfUse = T::TermsOfUse;
171    type Evidence = T::Evidence;
172    type Schema = T::Schema;
173
174    fn id(&self) -> Option<&Uri> {
175        T::id(&self.claims)
176    }
177
178    fn additional_types(&self) -> &[String] {
179        T::additional_types(&self.claims)
180    }
181
182    fn credential_subjects(&self) -> &[Self::Subject] {
183        T::credential_subjects(&self.claims)
184    }
185
186    fn issuer(&self) -> &Self::Issuer {
187        T::issuer(&self.claims)
188    }
189
190    fn issuance_date(&self) -> Option<DateTime> {
191        T::issuance_date(&self.claims)
192    }
193
194    fn expiration_date(&self) -> Option<DateTime> {
195        T::expiration_date(&self.claims)
196    }
197
198    fn credential_status(&self) -> &[Self::Status] {
199        T::credential_status(&self.claims)
200    }
201
202    fn refresh_services(&self) -> &[Self::RefreshService] {
203        T::refresh_services(&self.claims)
204    }
205
206    fn terms_of_use(&self) -> &[Self::TermsOfUse] {
207        T::terms_of_use(&self.claims)
208    }
209
210    fn evidence(&self) -> &[Self::Evidence] {
211        T::evidence(&self.claims)
212    }
213
214    fn credential_schemas(&self) -> &[Self::Schema] {
215        T::credential_schemas(&self.claims)
216    }
217}
218
219pub struct CredentialTypes<'a> {
220    base_type: bool,
221    additional_types: std::slice::Iter<'a, String>,
222}
223
224impl<'a> CredentialTypes<'a> {
225    pub fn from_additional_types(additional_types: &'a [String]) -> Self {
226        Self {
227            base_type: true,
228            additional_types: additional_types.iter(),
229        }
230    }
231}
232
233impl<'a> Iterator for CredentialTypes<'a> {
234    type Item = &'a str;
235
236    fn next(&mut self) -> Option<Self::Item> {
237        if self.base_type {
238            self.base_type = false;
239            Some(VERIFIABLE_CREDENTIAL_TYPE)
240        } else {
241            self.additional_types.next().map(String::as_str)
242        }
243    }
244}