1
//! Certificate related types and functions for an arti relay.
2

            
3
use tor_cert::{CertEncodeError, CertType, CertifiedKey, Ed25519Cert, EncodedEd25519Cert};
4
use tor_checkable::{SelfSigned, Timebound};
5
use tor_key_forge::{InvalidCertError, ParsedEd25519Cert, ToEncodableCert};
6
use tor_llcrypto::pk::ed25519::{self, Ed25519Identity};
7
use web_time_compat::{SystemTime, SystemTimeExt};
8

            
9
use crate::pk::{RelayIdentityKeypair, RelayLinkSigningKeypair, RelaySigningKeypair};
10

            
11
// TODO: maybe we can eventually unify the 2 `gen_*_cert` functions
12
// into a single one taking a `K: HasCertType` generic param and returning `Result<K>`.
13
// That way, we could call `K::cert_type()` to get the cert type,
14
// making it impossible for the `gen_*_cert function to accidentally use
15
// a different cert type than the validation function.
16

            
17
/// Generate the relay signing certificate from the given relay identity keypair and the relay
18
/// signing keypair.
19
714
pub fn gen_signing_cert(
20
714
    kp_relay_id: &RelayIdentityKeypair,
21
714
    kp_relaysign_id: &RelaySigningKeypair,
22
714
    expiry: SystemTime,
23
714
) -> Result<RelaySigningKeyCert, CertEncodeError> {
24
714
    Ed25519Cert::constructor()
25
714
        .cert_type(RelaySigningKeyCert::cert_type())
26
714
        .expiration(expiry)
27
714
        .signing_key(kp_relay_id.to_ed25519_id())
28
714
        .cert_key(CertifiedKey::Ed25519(kp_relaysign_id.to_ed25519_id()))
29
714
        .encode_and_sign(kp_relay_id)
30
714
        .map(RelaySigningKeyCert::from)
31
714
}
32

            
33
/// Generate the relay link certificate from the given relay signing keypair and the relay
34
/// link keypair.
35
102
pub fn gen_link_cert(
36
102
    kp_relaysign_id: &RelaySigningKeypair,
37
102
    kp_link_id: &RelayLinkSigningKeypair,
38
102
    expiry: SystemTime,
39
102
) -> Result<RelayLinkSigningKeyCert, CertEncodeError> {
40
102
    Ed25519Cert::constructor()
41
102
        .cert_type(RelayLinkSigningKeyCert::cert_type())
42
102
        .expiration(expiry)
43
102
        .signing_key(kp_relaysign_id.to_ed25519_id())
44
102
        .cert_key(CertifiedKey::Ed25519(kp_link_id.to_ed25519_id()))
45
102
        .encode_and_sign(kp_relaysign_id)
46
102
        .map(RelayLinkSigningKeyCert::from)
47
102
}
48

            
49
/// Generate the signed TLS certificate from the given relay signing keypair and the TLS cert
50
/// digest.
51
102
pub fn gen_tls_cert(
52
102
    kp_relaysign_id: &RelaySigningKeypair,
53
102
    tls_digest: [u8; 32],
54
102
    expiry: SystemTime,
55
102
) -> Result<EncodedEd25519Cert, CertEncodeError> {
56
102
    Ed25519Cert::constructor()
57
102
        .cert_type(CertType::SIGNING_V_TLS_CERT)
58
102
        .expiration(expiry)
59
102
        .signing_key(kp_relaysign_id.to_ed25519_id())
60
102
        .cert_key(CertifiedKey::X509Sha256Digest(tls_digest))
61
102
        .encode_and_sign(kp_relaysign_id)
62
102
}
63

            
64
/// Certificate for the medium-term relay signing key (`K_relaysign_ed`).
65
///
66
/// This is an ed25519 certificate encoded in Tor's
67
/// [certificate format](https://spec.torproject.org/cert-spec.html#ed-certs)
68
/// with [`CERT_KEY_TYPE`](https://spec.torproject.org/cert-spec.html#list-key-types)
69
/// set to `ed25519` (`01`),
70
/// and the [`CERT_TYPE`](https://spec.torproject.org/cert-spec.html#list-cert-types)
71
/// set to `IDENTITY_V_SIGNING` (`04`).
72
///
73
/// The signing key is the relay identity key (`K_relayid_ed`)`).
74
#[derive(Debug, Clone, PartialEq, derive_more::From)]
75
pub struct RelaySigningKeyCert(EncodedEd25519Cert);
76

            
77
impl RelaySigningKeyCert {
78
    /// Return the `CertType` of this cert.
79
714
    fn cert_type() -> CertType {
80
714
        CertType::IDENTITY_V_SIGNING
81
714
    }
82
}
83

            
84
/// Certificate for the short-term signing keypair for link authentication.
85
///
86
/// This is an ed25519 certificate encoded in Tor's
87
/// [certificate format](https://spec.torproject.org/cert-spec.html#ed-certs)
88
/// with [`CERT_KEY_TYPE`](https://spec.torproject.org/cert-spec.html#list-key-types)
89
/// set to `ed25519` (`01`),
90
/// and the [`CERT_TYPE`](https://spec.torproject.org/cert-spec.html#list-cert-types)
91
/// set to `SIGNING_V_LINK_AUTH` (`06`).
92
///
93
/// The signing key is the relay identity key (`K_relayid_ed`)`).
94
#[derive(Debug, Clone, PartialEq, derive_more::From)]
95
pub struct RelayLinkSigningKeyCert(EncodedEd25519Cert);
96

            
97
impl RelayLinkSigningKeyCert {
98
    /// Return the `CertType` of this cert.
99
102
    fn cert_type() -> CertType {
100
102
        CertType::SIGNING_V_LINK_AUTH
101
102
    }
102
}
103

            
104
impl ToEncodableCert<RelaySigningKeypair> for RelaySigningKeyCert {
105
    type ParsedCert = ParsedEd25519Cert;
106
    type EncodableCert = EncodedEd25519Cert;
107
    type SigningKey = RelayIdentityKeypair;
108

            
109
    fn validate(
110
        cert: Self::ParsedCert,
111
        subject: &RelaySigningKeypair,
112
        signed_with: &Self::SigningKey,
113
    ) -> Result<Self, InvalidCertError> {
114
        // TODO: take the time/time provider as an arg?
115
        let now = SystemTime::get();
116
        validate_ed25519_cert(
117
            cert,
118
            &subject.public().into(),
119
            &signed_with.public().into(),
120
            Self::cert_type(),
121
            &now,
122
        )
123
        .map(RelaySigningKeyCert::from)
124
    }
125

            
126
714
    fn to_encodable_cert(self) -> Self::EncodableCert {
127
714
        self.0
128
714
    }
129
}
130

            
131
impl ToEncodableCert<RelayLinkSigningKeypair> for RelayLinkSigningKeyCert {
132
    type ParsedCert = ParsedEd25519Cert;
133
    type EncodableCert = EncodedEd25519Cert;
134
    type SigningKey = RelaySigningKeypair;
135

            
136
    fn validate(
137
        cert: Self::ParsedCert,
138
        subject: &RelayLinkSigningKeypair,
139
        signed_with: &Self::SigningKey,
140
    ) -> Result<Self, InvalidCertError> {
141
        // TODO: take the time/time provider as an arg?
142
        let now = SystemTime::get();
143
        validate_ed25519_cert(
144
            cert,
145
            &subject.public().into(),
146
            &signed_with.public().into(),
147
            Self::cert_type(),
148
            &now,
149
        )
150
        .map(RelayLinkSigningKeyCert::from)
151
    }
152

            
153
102
    fn to_encodable_cert(self) -> Self::EncodableCert {
154
102
        self.0
155
102
    }
156
}
157

            
158
/// Validate the specified `cert`, checking that
159
///    * its [`CertType`] is `cert_type, and
160
///    * its subject key is `subject`, and
161
///    * it is signed with the `signed_with` key, and
162
///    * it is timely (it is not expired or not yet valid at the specified `ts`)
163
fn validate_ed25519_cert(
164
    cert: ParsedEd25519Cert,
165
    subject: &ed25519::PublicKey,
166
    signed_with: &ed25519::PublicKey,
167
    cert_type: CertType,
168
    ts: &SystemTime,
169
) -> Result<EncodedEd25519Cert, InvalidCertError> {
170
    let cert = cert
171
        .should_be_signed_with(&Ed25519Identity::from(signed_with))?
172
        .check_signature()?;
173

            
174
    let cert = cert.check_valid_at(ts)?;
175
    let subject = Ed25519Identity::from(subject);
176

            
177
    if subject != *cert.subject_key()? {
178
        return Err(InvalidCertError::SubjectKeyMismatch);
179
    }
180

            
181
    let actual_cert_type = cert.as_ref().cert_type();
182
    if actual_cert_type != cert_type {
183
        return Err(InvalidCertError::CertType(actual_cert_type));
184
    }
185

            
186
    Ok(cert.into_encoded())
187
}