tor_relay_crypto/
certs.rs

1//! Certificate related types and functions for an arti relay.
2
3use std::time::SystemTime;
4
5use tor_cert::{CertEncodeError, CertType, CertifiedKey, Ed25519Cert, EncodedEd25519Cert};
6use tor_checkable::{SelfSigned, Timebound};
7use tor_key_forge::{InvalidCertError, ParsedEd25519Cert, ToEncodableCert};
8use tor_llcrypto::pk::ed25519::{self, Ed25519Identity};
9
10use 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.
20pub fn gen_signing_cert(
21    kp_relay_id: &RelayIdentityKeypair,
22    kp_relaysign_id: &RelaySigningKeypair,
23    expiry: SystemTime,
24) -> Result<RelayLinkSigningKeyCert, CertEncodeError> {
25    Ed25519Cert::constructor()
26        .cert_type(RelayLinkSigningKeyCert::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(RelayLinkSigningKeyCert::from)
32}
33
34/// Generate the relay link certificate from the given relay signing keypair and the relay
35/// link keypair.
36pub 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/// Certificate for the medium-term relay signing key (`K_relaysign_ed`).
51///
52/// This is an ed25519 certificate encoded in Tor's
53/// [certificate format](https://spec.torproject.org/cert-spec.html#ed-certs)
54/// with [`CERT_KEY_TYPE`](https://spec.torproject.org/cert-spec.html#list-key-types)
55/// set to `ed25519` (`01`),
56/// and the [`CERT_TYPE`](https://spec.torproject.org/cert-spec.html#list-cert-types)
57/// set to `IDENTITY_V_SIGNING` (`04`).
58///
59/// The signing key is the relay identity key (`K_relayid_ed`)`).
60#[derive(Debug, Clone, PartialEq, derive_more::From)]
61pub struct RelaySigningKeyCert(EncodedEd25519Cert);
62
63impl RelaySigningKeyCert {
64    /// Return the `CertType` of this cert.
65    fn cert_type() -> CertType {
66        CertType::IDENTITY_V_SIGNING
67    }
68}
69
70/// Certificate for the short-term signing keypair for link authentication.
71///
72/// This is an ed25519 certificate encoded in Tor's
73/// [certificate format](https://spec.torproject.org/cert-spec.html#ed-certs)
74/// with [`CERT_KEY_TYPE`](https://spec.torproject.org/cert-spec.html#list-key-types)
75/// set to `ed25519` (`01`),
76/// and the [`CERT_TYPE`](https://spec.torproject.org/cert-spec.html#list-cert-types)
77/// set to `SIGNING_V_LINK_AUTH` (`06`).
78///
79/// The signing key is the relay identity key (`K_relayid_ed`)`).
80#[derive(Debug, Clone, PartialEq, derive_more::From)]
81pub struct RelayLinkSigningKeyCert(EncodedEd25519Cert);
82
83impl RelayLinkSigningKeyCert {
84    /// Return the `CertType` of this cert.
85    fn cert_type() -> CertType {
86        CertType::SIGNING_V_LINK_AUTH
87    }
88}
89
90impl ToEncodableCert<RelaySigningKeypair> for RelaySigningKeyCert {
91    type ParsedCert = ParsedEd25519Cert;
92    type EncodableCert = EncodedEd25519Cert;
93    type SigningKey = RelayIdentityKeypair;
94
95    fn validate(
96        cert: Self::ParsedCert,
97        subject: &RelaySigningKeypair,
98        signed_with: &Self::SigningKey,
99    ) -> Result<Self, InvalidCertError> {
100        // TODO: take the time/time provider as an arg?
101        let now = SystemTime::now();
102        validate_ed25519_cert(
103            cert,
104            &subject.public().into(),
105            &signed_with.public().into(),
106            Self::cert_type(),
107            &now,
108        )
109        .map(RelaySigningKeyCert::from)
110    }
111
112    fn to_encodable_cert(self) -> Self::EncodableCert {
113        self.0
114    }
115}
116
117impl ToEncodableCert<RelayLinkSigningKeypair> for RelayLinkSigningKeyCert {
118    type ParsedCert = ParsedEd25519Cert;
119    type EncodableCert = EncodedEd25519Cert;
120    type SigningKey = RelaySigningKeypair;
121
122    fn validate(
123        cert: Self::ParsedCert,
124        subject: &RelayLinkSigningKeypair,
125        signed_with: &Self::SigningKey,
126    ) -> Result<Self, InvalidCertError> {
127        // TODO: take the time/time provider as an arg?
128        let now = SystemTime::now();
129        validate_ed25519_cert(
130            cert,
131            &subject.public().into(),
132            &signed_with.public().into(),
133            Self::cert_type(),
134            &now,
135        )
136        .map(RelayLinkSigningKeyCert::from)
137    }
138
139    fn to_encodable_cert(self) -> Self::EncodableCert {
140        self.0
141    }
142}
143
144/// Validate the specified `cert`, checking that
145///    * its [`CertType`] is `cert_type, and
146///    * its subject key is `subject`, and
147///    * it is signed with the `signed_with` key, and
148///    * it is timely (it is not expired or not yet valid at the specified `ts`)
149fn validate_ed25519_cert(
150    cert: ParsedEd25519Cert,
151    subject: &ed25519::PublicKey,
152    signed_with: &ed25519::PublicKey,
153    cert_type: CertType,
154    ts: &SystemTime,
155) -> Result<EncodedEd25519Cert, InvalidCertError> {
156    let cert = cert
157        .should_be_signed_with(&Ed25519Identity::from(signed_with))?
158        .check_signature()?;
159
160    let cert = cert.check_valid_at(ts)?;
161    let subject = Ed25519Identity::from(subject);
162
163    if subject != *cert.subject_key()? {
164        return Err(InvalidCertError::SubjectKeyMismatch);
165    }
166
167    let actual_cert_type = cert.as_ref().cert_type();
168    if actual_cert_type != cert_type {
169        return Err(InvalidCertError::CertType(actual_cert_type));
170    }
171
172    Ok(cert.into_encoded())
173}