File: expired-cert.rs

package info (click to toggle)
rust-sequoia-git 0.4.0-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,580 kB
  • sloc: sh: 367; makefile: 32
file content (175 lines) | stat: -rw-r--r-- 5,179 bytes parent folder | download
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
use std::fs;
use std::time::Duration;
use std::time::SystemTime;

use sequoia_openpgp as openpgp;
use openpgp::Packet;
use openpgp::policy::StandardPolicy;

const P: &StandardPolicy = &StandardPolicy::new();

mod common;
use common::Environment;

#[test]
fn expired_certificate() -> anyhow::Result<()> {
    if ! Environment::check_for_faketime()? {
        // faketime tests are disabled.
        return Ok(());
    }

    // Consider:
    //
    // Alice is authorized to add commits at time t0.
    let t0 = SystemTime::now() - Duration::new(80 * 60, 0);
    //
    // At t1, she adds a commit (c1).
    let t1 = t0 + Duration::new(30 * 60, 0);
    // At t2, her certificate expires.
    //
    // Note: This corresponds to the current time, because
    // set_expiration_time doesn't let us override the signature
    // creation time.  See:
    //
    //   https://gitlab.com/sequoia-pgp/sequoia/-/issues/1154
    let t2 = t1 + Duration::new(50 * 60, 0);
    //
    // At t3, she adds a commit (c2) that updates her certificate.
    let t3 = t2 + Duration::new(70 * 60, 0);

    let future = t3 + Duration::new(110 * 60, 0);
    //
    // The policy in c1 is used to authenticate c2, but the
    // certificate in c1's policy is expired.  In this case, the
    // certificates from c2's policy should be used to update the
    // certificates in c1's policy.

    let mut e = Environment::at(t0.clone())?;
    let p = e.git_state();

    let (alice, alice_pgp) = e.gen(
        "alice",
        t0.clone(),
        t2.duration_since(t1.clone()).expect("valid"));
    let alice_fpr = &alice.fingerprint().to_string()[..];

    e.sq_git(&[
        "policy",
        "authorize",
        "alice",
        "--cert-file", &alice_pgp,
        "--sign-commit"
    ])?;
    e.git(&["add", "openpgp-policy.toml"])?;
    e.git(&[
        "commit",
        "-m", "Initial commit (@ t0).",
    ])?;
    let root = e.git_current_commit()?;

    e.git(&["log"])?;
    e.sq_git(&["log", "--trust-root", &root])?;

    // Add another commit at t1.
    e.time(t1);

    fs::write(p.join("2"), "2.")?;
    e.git(&["add", "2"])?;
    e.git(&[
        "commit",
        "-m", "@ t1",
        &format!("-S{}", alice_fpr),
    ])?;
    let c2 = e.git_current_commit()?;

    e.git(&["log"])?;
    e.sq_git(&["log", "--trust-root", &root, &c2])?;

    // Try adding a commit after her certificate expires.  This should fail.
    e.time(t3);

    fs::write(p.join("3"), "3.")?;
    e.git(&["add", "3"])?;
    assert!(e.git(&[
        "commit",
        "-m", "@ t3.",
        &format!("-S{}", alice_fpr),
    ]).is_err());


    // Extend Alice's expiration.
    let (alice2, _) = {
        let vc = alice.with_policy(P, e.time.clone()).expect("valid cert");

        let mut primary_signer = alice.primary_key().key().clone()
            .parts_into_secret()?.into_keypair()?;

        // We really want to set the new signatures' creation time to t2

        let mut packets = Vec::new();
        for ka in vc.keys() {
            let mut subkey_signer = if ka.for_signing() {
                Some(ka.key().clone().parts_into_secret()?.into_keypair()?)
            } else {
                None
            };

            let sigs = ka.set_expiration_time(
                &mut primary_signer,
                if let Some(subkey_signer) = subkey_signer.as_mut() {
                    Some(subkey_signer)
                } else {
                    None
                },
                Some(future.clone()))
                .expect(&format!("can update expiration of {}", ka.key().fingerprint()));
            if ka.key().fingerprint() == alice.fingerprint() {
                packets.push(Packet::from(alice.primary_key().key().clone()));
            } else {
                packets.push(Packet::from(ka.key().clone().role_into_subordinate()));
            }
            packets.extend(sigs.into_iter().map(|sig| Packet::from(sig)));
        }

        alice.clone().insert_packets(packets).expect("can insert packets")
    };

    e.import(&alice2).expect("can import");

    // Now we should be able to create the commit.
    assert!(e.git(&[
        "commit",
        "-m", "@ t3.",
        &format!("-S{}", alice_fpr),
    ]).is_ok());
    let c3_1 = e.git_current_commit()?;

    // But we can't verify it, because the certificate in the policy
    // is expired!
    e.git(&["log"])?;
    assert!(e.sq_git(&["log", "--trust-root", &root, &c3_1]).is_err());

    // Reset to c2.
    e.git(&["reset", "--hard", &c2])?;
    assert_eq!(c2, e.git_current_commit()?);

    // Update the policy (by looking in the local certificate store).
    assert!(e.sq_git(&["policy", "sync", "--disable-keyservers"]).is_ok());

    e.git(&["add", "openpgp-policy.toml"])?;

    // Now we should be able to create the commit.
    assert!(e.git(&[
        "commit",
        "-m", "@ t3 (try two).",
        &format!("-S{}", alice_fpr),
    ]).is_ok());
    let c3_2 = e.git_current_commit()?;

    // And we can verify it, because the updated certificate is in the
    // new commit's policy file.
    e.git(&["log"])?;
    assert!(e.sq_git(&["log", "--trust-root", &root, &c3_2]).is_ok());

    Ok(())
}