trust_graph/
revoke.rs

1/*
2 * Copyright 2020 Fluence Labs Limited
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17use crate::revoke::RevokeError::IncorrectSignature;
18use fluence_keypair::key_pair::KeyPair;
19use fluence_keypair::public_key::PublicKey;
20use fluence_keypair::signature::Signature;
21use serde::{Deserialize, Serialize};
22use sha2::Digest;
23use std::time::Duration;
24use thiserror::Error as ThisError;
25
26#[derive(ThisError, Debug)]
27pub enum RevokeError {
28    #[error("Signature is incorrect: {0}")]
29    IncorrectSignature(
30        #[from]
31        #[source]
32        fluence_keypair::error::VerificationError,
33    ),
34}
35
36/// "A document" that cancels trust created before.
37/// TODO delete pk from Revoke (it is already in a trust node)
38#[derive(Clone, Debug, Serialize, Deserialize)]
39pub struct Revocation {
40    /// who is revoked
41    pub pk: PublicKey,
42    /// date when revocation was created
43    pub revoked_at: Duration,
44    /// the issuer of this revocation
45    pub revoked_by: PublicKey,
46    /// proof of this revocation
47    pub signature: Signature,
48}
49
50impl Revocation {
51    pub fn new(
52        revoked_by: PublicKey,
53        pk: PublicKey,
54        revoked_at: Duration,
55        signature: Signature,
56    ) -> Self {
57        Self {
58            pk,
59            revoked_at,
60            revoked_by,
61            signature,
62        }
63    }
64
65    /// Creates new revocation signed by a revoker.
66    pub fn create(revoker: &KeyPair, to_revoke: PublicKey, revoked_at: Duration) -> Self {
67        let msg = Revocation::signature_bytes(&to_revoke, revoked_at);
68        let signature = revoker.sign(&msg).unwrap();
69
70        Revocation::new(revoker.public(), to_revoke, revoked_at, signature)
71    }
72
73    pub fn signature_bytes(pk: &PublicKey, revoked_at: Duration) -> Vec<u8> {
74        let mut metadata = Vec::new();
75        let pk_bytes = &pk.encode();
76        metadata.push(pk_bytes.len() as u8);
77        metadata.extend(pk_bytes);
78        metadata.extend_from_slice(&revoked_at.as_secs().to_le_bytes());
79
80        sha2::Sha256::digest(&metadata).to_vec()
81    }
82
83    /// Verifies that revocation is cryptographically correct.
84    pub fn verify(revoke: &Revocation) -> Result<(), RevokeError> {
85        let msg = Revocation::signature_bytes(&revoke.pk, revoke.revoked_at);
86
87        revoke
88            .revoked_by
89            .verify(msg.as_slice(), &revoke.signature)
90            .map_err(IncorrectSignature)
91    }
92}
93
94#[cfg(test)]
95mod tests {
96    use super::*;
97
98    #[test]
99    fn test_gen_revoke_and_validate_ed25519() {
100        let revoker = KeyPair::generate_ed25519();
101        let to_revoke = KeyPair::generate_ed25519();
102
103        let duration = Duration::new(100, 0);
104
105        let revoke = Revocation::create(&revoker, to_revoke.public(), duration);
106
107        assert_eq!(Revocation::verify(&revoke).is_ok(), true);
108    }
109
110    #[test]
111    fn test_validate_corrupted_revoke_ed25519() {
112        let revoker = KeyPair::generate_ed25519();
113        let to_revoke = KeyPair::generate_ed25519();
114
115        let duration = Duration::new(100, 0);
116
117        let revoke = Revocation::create(&revoker, to_revoke.public(), duration);
118
119        let duration2 = Duration::new(95, 0);
120        let corrupted_revoke = Revocation::new(
121            revoker.public(),
122            to_revoke.public(),
123            duration2,
124            revoke.signature,
125        );
126
127        assert_eq!(Revocation::verify(&corrupted_revoke).is_ok(), false);
128    }
129}