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

            
3
use std::time::SystemTime;
4

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            
187
    Ok(cert.into_encoded())
188
}