/ crates / tor-relay-crypto / src / certs.rs
certs.rs
  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<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.
 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  /// 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)]
 61  pub struct RelaySigningKeyCert(EncodedEd25519Cert);
 62  
 63  impl 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)]
 81  pub struct RelayLinkSigningKeyCert(EncodedEd25519Cert);
 82  
 83  impl RelayLinkSigningKeyCert {
 84      /// Return the `CertType` of this cert.
 85      fn cert_type() -> CertType {
 86          CertType::SIGNING_V_LINK_AUTH
 87      }
 88  }
 89  
 90  impl 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  
117  impl 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`)
149  fn 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  }