1pub(crate) mod create_handler;
7pub(crate) mod handshake;
8pub(crate) mod initiator;
9pub(crate) mod responder;
10
11pub use responder::MaybeVerifiableRelayResponderChannel;
12
13use digest::Digest;
14use futures::{AsyncRead, AsyncWrite};
15use rand::Rng;
16use safelog::Sensitive;
17use std::net::{IpAddr, SocketAddr};
18use std::sync::Arc;
19use std::time::UNIX_EPOCH;
20
21use tor_cell::chancell::msg;
22use tor_cert::EncodedEd25519Cert;
23use tor_cert::rsa::EncodedRsaCrosscert;
24use tor_cert::x509::TlsKeyAndCert;
25use tor_error::internal;
26use tor_linkspec::{HasRelayIds, OwnedChanTarget, RelayIdRef, RelayIdType};
27use tor_llcrypto as ll;
28use tor_llcrypto::pk::{
29 ed25519::{Ed25519Identity, Ed25519SigningKey},
30 rsa,
31 rsa::RsaIdentity,
32};
33use tor_relay_crypto::pk::RelayLinkSigningKeypair;
34use tor_rtcompat::{CertifiedConn, CoarseTimeProvider, SleepProvider, StreamOps};
35
36use crate::channel::handshake::VerifiedChannel;
37use crate::channel::{ClogDigest, SlogDigest};
38use crate::peer::PeerAddr;
39use crate::relay::CreateRequestHandler;
40use crate::relay::channel::handshake::{AUTHTYPE_ED25519_SHA256_RFC5705, RelayResponderHandshake};
41use crate::{Error, Result, channel::RelayInitiatorHandshake, memquota::ChannelAccount};
42
43pub(crate) static LINK_AUTH: &[u16] = &[AUTHTYPE_ED25519_SHA256_RFC5705];
47
48pub struct RelayChannelAuthMaterial {
53 pub(crate) rsa_id_der_digest: [u8; 32],
55 pub(crate) rsa_id: RsaIdentity,
58 pub(crate) ed_id: Ed25519Identity,
60 pub(crate) link_sign_kp: RelayLinkSigningKeypair,
62 pub(crate) cert_id_sign_ed: EncodedEd25519Cert,
64 pub(crate) cert_sign_tls_ed: EncodedEd25519Cert,
66 pub(crate) cert_sign_link_auth_ed: EncodedEd25519Cert,
68 pub(crate) cert_id_x509_rsa: Vec<u8>,
73 pub(crate) cert_id_rsa: EncodedRsaCrosscert,
75 pub(crate) tls_key_and_cert: TlsKeyAndCert,
78}
79
80impl RelayChannelAuthMaterial {
81 #[allow(clippy::too_many_arguments)] pub fn new(
84 rsa_id_pk: &rsa::PublicKey,
85 ed_id: Ed25519Identity,
86 link_sign_kp: RelayLinkSigningKeypair,
87 cert_id_sign_ed: EncodedEd25519Cert,
88 cert_sign_tls_ed: EncodedEd25519Cert,
89 cert_sign_link_auth_ed: EncodedEd25519Cert,
90 cert_id_x509_rsa: Vec<u8>,
91 cert_id_rsa: EncodedRsaCrosscert,
92 tls_key_and_cert: TlsKeyAndCert,
93 ) -> Self {
94 Self {
95 rsa_id_der_digest: ll::d::Sha256::digest(rsa_id_pk.to_der()).into(),
96 rsa_id: rsa_id_pk.to_rsa_identity(),
97 ed_id,
98 link_sign_kp,
99 cert_id_sign_ed,
100 cert_sign_tls_ed,
101 cert_sign_link_auth_ed,
102 cert_id_x509_rsa,
103 cert_id_rsa,
104 tls_key_and_cert,
105 }
106 }
107
108 pub fn tls_key_and_cert(&self) -> &TlsKeyAndCert {
112 &self.tls_key_and_cert
113 }
114
115 pub(crate) fn ed_id_bytes(&self) -> [u8; 32] {
117 self.ed_id.into()
118 }
119}
120
121impl HasRelayIds for RelayChannelAuthMaterial {
122 fn identity(&self, key_type: RelayIdType) -> Option<RelayIdRef<'_>> {
123 match key_type {
124 RelayIdType::Ed25519 => Some(RelayIdRef::from(&self.ed_id)),
125 RelayIdType::Rsa => Some(RelayIdRef::from(&self.rsa_id)),
126 _ => None, }
128 }
129}
130
131#[derive(Default)]
133#[non_exhaustive]
134pub struct RelayChannelBuilder;
135
136impl RelayChannelBuilder {
137 pub fn new() -> Self {
139 Self::default()
140 }
141
142 #[allow(clippy::too_many_arguments)] pub fn launch<T, S>(
150 self,
151 tls: T,
152 sleep_prov: S,
153 auth_material: Arc<RelayChannelAuthMaterial>,
154 my_addrs: Vec<SocketAddr>,
155 peer_target: &OwnedChanTarget,
156 memquota: ChannelAccount,
157 create_request_handler: Arc<CreateRequestHandler>,
158 ) -> RelayInitiatorHandshake<T, S>
159 where
160 T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
161 S: CoarseTimeProvider + SleepProvider,
162 {
163 RelayInitiatorHandshake::new(
164 tls,
165 sleep_prov,
166 auth_material,
167 my_addrs,
168 peer_target,
169 memquota,
170 create_request_handler,
171 )
172 }
173
174 #[expect(clippy::too_many_arguments)]
176 pub fn accept<T, S>(
177 self,
178 peer_addr: Sensitive<PeerAddr>,
179 my_addrs: Vec<SocketAddr>,
180 tls: T,
181 sleep_prov: S,
182 auth_material: Arc<RelayChannelAuthMaterial>,
183 memquota: ChannelAccount,
184 create_request_handler: Arc<CreateRequestHandler>,
185 ) -> RelayResponderHandshake<T, S>
186 where
187 T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
188 S: CoarseTimeProvider + SleepProvider,
189 {
190 RelayResponderHandshake::new(
191 peer_addr,
192 my_addrs,
193 tls,
194 sleep_prov,
195 auth_material,
196 memquota,
197 create_request_handler,
198 )
199 }
200}
201
202pub(crate) struct ChannelAuthenticationData {
205 pub(crate) link_auth: u16,
207 pub(crate) cid: [u8; 32],
209 pub(crate) sid: [u8; 32],
211 pub(crate) cid_ed: [u8; 32],
213 pub(crate) sid_ed: [u8; 32],
215 pub(crate) clog: ClogDigest,
217 pub(crate) slog: SlogDigest,
219 pub(crate) scert: [u8; 32],
221}
222
223impl ChannelAuthenticationData {
224 const fn auth_type_bytes(link_auth: u16) -> Result<&'static [u8]> {
226 match link_auth {
227 3 => Ok(b"AUTH0003"),
228 _ => Err(Error::BadCellAuth),
229 }
230 }
231
232 const fn keying_material_label_bytes(link_auth: u16) -> Result<&'static [u8]> {
234 match link_auth {
235 3 => Ok(b"EXPORTER FOR TOR TLS CLIENT BINDING AUTH0003"),
236 _ => Err(Error::BadCellAuth),
237 }
238 }
239
240 pub(crate) fn as_body_no_rand<C: CertifiedConn>(&self, tls: &C) -> Result<Vec<u8>> {
247 let mut body = Vec::with_capacity(msg::Authenticate::BODY_LEN);
249
250 body.extend_from_slice(Self::auth_type_bytes(self.link_auth)?);
252 body.extend_from_slice(&self.cid);
253 body.extend_from_slice(&self.sid);
254 body.extend_from_slice(&self.cid_ed);
255 body.extend_from_slice(&self.sid_ed);
256 body.extend_from_slice(self.slog.as_ref());
257 body.extend_from_slice(self.clog.as_ref());
258 body.extend_from_slice(&self.scert);
259
260 let tls_secrets = tls.export_keying_material(
262 32,
263 Self::keying_material_label_bytes(self.link_auth)?,
264 Some(&self.cid[..]),
265 )?;
266 body.extend_from_slice(tls_secrets.as_slice());
267
268 debug_assert_eq!(body.len(), msg::Authenticate::BODY_LEN);
270 debug_assert_eq!(body.capacity(), msg::Authenticate::BODY_LEN);
271
272 Ok(body)
273 }
274
275 pub(crate) fn into_authenticate<C: CertifiedConn>(
277 self,
278 tls: &C,
279 link_ed: &RelayLinkSigningKeypair,
280 ) -> Result<msg::Authenticate> {
281 let mut body = self.as_body_no_rand(tls)?;
283
284 let random: [u8; 24] = rand::rng().random();
286 body.extend_from_slice(&random);
287
288 let sig = link_ed.sign(&body);
291 body.extend_from_slice(&sig.to_bytes());
292
293 Ok(msg::Authenticate::new(self.link_auth, body))
295 }
296
297 pub(crate) fn build_initiator<T, S>(
307 auth_challenge_cell: &msg::AuthChallenge,
308 auth_material: &Arc<RelayChannelAuthMaterial>,
309 clog: ClogDigest,
310 slog: SlogDigest,
311 verified: &mut VerifiedChannel<T, S>,
312 peer_cert_digest: [u8; 32],
313 ) -> Result<ChannelAuthenticationData>
314 where
315 T: AsyncRead + AsyncWrite + CertifiedConn + StreamOps + Send + Unpin + 'static,
316 S: CoarseTimeProvider + SleepProvider,
317 {
318 let link_auth = *LINK_AUTH
320 .iter()
321 .filter(|m| auth_challenge_cell.methods().contains(m))
322 .max()
323 .ok_or(Error::BadCellAuth)?;
324 let cid = auth_material.rsa_id_der_digest;
326 let sid = verified.peer_rsa_id_digest;
327 let cid_ed = auth_material.ed_id_bytes();
328 let sid_ed = (*verified
329 .relay_ids()
330 .ed_identity()
331 .expect("Verified channel without Ed25519 identity"))
332 .into();
333
334 Ok(Self {
335 link_auth,
336 cid,
337 sid,
338 cid_ed,
339 sid_ed,
340 clog,
341 slog,
342 scert: peer_cert_digest,
343 })
344 }
345
346 pub(crate) fn build_responder(
360 initiator_auth_type: u16,
361 auth_material: &Arc<RelayChannelAuthMaterial>,
362 clog: ClogDigest,
363 slog: SlogDigest,
364 peer_rsa_id_digest: [u8; 32],
365 peer_relayid_ed: Ed25519Identity,
366 our_cert_digest: [u8; 32],
367 ) -> Result<ChannelAuthenticationData> {
368 let link_auth = if LINK_AUTH.contains(&initiator_auth_type) {
370 initiator_auth_type
371 } else {
372 return Err(Error::UnsupportedAuth(initiator_auth_type));
373 };
374 let cid = auth_material.rsa_id_der_digest;
376 let sid = peer_rsa_id_digest;
377 let cid_ed = auth_material.ed_id_bytes();
378 let sid_ed = peer_relayid_ed.into();
379
380 Ok(Self {
381 link_auth,
382 cid: sid,
384 sid: cid,
385 cid_ed: sid_ed,
386 sid_ed: cid_ed,
387 clog,
388 slog,
389 scert: our_cert_digest,
390 })
391 }
392}
393
394pub(crate) fn build_certs_cell(
398 auth_material: &Arc<RelayChannelAuthMaterial>,
399 is_responder: bool,
400) -> msg::Certs {
401 let mut certs = msg::Certs::new_empty();
402 certs.push_cert_body(
404 tor_cert::CertType::RSA_ID_X509,
405 auth_material.cert_id_x509_rsa.clone(),
406 );
407
408 certs.push_cert(&auth_material.cert_id_rsa);
410
411 certs.push_cert(&auth_material.cert_id_sign_ed);
413 if is_responder {
415 certs.push_cert(&auth_material.cert_sign_tls_ed);
417 } else {
418 certs.push_cert(&auth_material.cert_sign_link_auth_ed);
420 }
421 certs
422}
423
424pub(crate) fn build_netinfo_cell<S>(
428 peer_ip: Option<IpAddr>,
429 my_addrs: Vec<IpAddr>,
430 sleep_prov: &S,
431) -> Result<msg::Netinfo>
432where
433 S: CoarseTimeProvider + SleepProvider,
434{
435 let timestamp = sleep_prov
438 .wallclock()
439 .duration_since(UNIX_EPOCH)
440 .map_err(|e| internal!("Wallclock may have gone backwards: {e}"))?
441 .as_secs()
442 .try_into()
443 .map_err(|e| internal!("Wallclock secs fail to convert to 32bit: {e}"))?;
444 Ok(msg::Netinfo::from_relay(timestamp, peer_ip, my_addrs))
445}
446
447#[cfg(test)]
448pub(crate) mod test {
449 #![allow(clippy::unwrap_used)]
450 use futures::channel::mpsc::{Receiver, Sender};
451 use futures::task::{Context, Poll};
452 use futures::{AsyncRead, AsyncWrite};
453 use std::borrow::Cow;
454 use std::io::Result as IoResult;
455 use std::pin::Pin;
456 use std::sync::{Arc, Mutex, OnceLock};
457 use std::time::{Duration, SystemTime};
458
459 use tor_basic_utils::test_rng::testing_rng;
460 use tor_cell::chancell::AnyChanCell;
461 use tor_cert::x509::TlsKeyAndCert;
462 use tor_key_forge::{Keygen, ToEncodableCert};
463 use tor_linkspec::OwnedChanTarget;
464 use tor_relay_crypto::pk::{
465 RelayIdentityKeypair, RelayIdentityRsaKeypair, RelayLinkSigningKeypair, RelaySigningKeypair,
466 };
467 use tor_relay_crypto::{gen_link_cert, gen_signing_cert, gen_tls_cert};
468 use tor_rtcompat::{CertifiedConn, Runtime, SpawnExt, StreamOps};
469 use web_time_compat::SystemTimeExt;
470
471 use crate::channel::Channel;
472 use crate::channel::handler::test::MsgBuf;
473 use crate::channel::test::{CodecResult, new_reactor};
474 use crate::circuit::UniqId;
475 use crate::relay::channel::RelayChannelAuthMaterial;
476 use crate::relay::channel_provider::{ChannelProvider, OutboundChanSender};
477
478 pub(crate) struct RelayMsgBuf(pub(crate) MsgBuf);
481
482 impl AsyncRead for RelayMsgBuf {
483 fn poll_read(
484 mut self: Pin<&mut Self>,
485 cx: &mut Context<'_>,
486 buf: &mut [u8],
487 ) -> Poll<IoResult<usize>> {
488 Pin::new(&mut self.0).poll_read(cx, buf)
489 }
490 }
491
492 impl AsyncWrite for RelayMsgBuf {
493 fn poll_write(
494 mut self: Pin<&mut Self>,
495 cx: &mut Context<'_>,
496 buf: &[u8],
497 ) -> Poll<IoResult<usize>> {
498 Pin::new(&mut self.0).poll_write(cx, buf)
499 }
500 fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<IoResult<()>> {
501 Pin::new(&mut self.0).poll_flush(cx)
502 }
503 fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<IoResult<()>> {
504 Pin::new(&mut self.0).poll_close(cx)
505 }
506 }
507
508 impl StreamOps for RelayMsgBuf {}
509
510 impl CertifiedConn for RelayMsgBuf {
511 fn export_keying_material(
512 &self,
513 len: usize,
514 _label: &[u8],
515 _context: Option<&[u8]>,
516 ) -> IoResult<Vec<u8>> {
517 Ok(vec![42_u8; len])
518 }
519 fn peer_certificate(&self) -> IoResult<Option<Cow<'_, [u8]>>> {
520 const ISSUER: &str = "issuer.peer_tls.test.nowar.net";
521 const SUBJECT: &str = "subject.peer_tls.test.nowar.net";
522 Ok(Some(fake_tls_cert(ISSUER, SUBJECT)))
523 }
524 fn own_certificate(&self) -> IoResult<Option<Cow<'_, [u8]>>> {
525 const ISSUER: &str = "issuer.own_tls.test.nowar.net";
526 const SUBJECT: &str = "subject.own_tls.test.nowar.net";
527 Ok(Some(fake_tls_cert(ISSUER, SUBJECT)))
528 }
529 }
530
531 fn fake_tls_cert<'a>(issuer: &'a str, subject: &'a str) -> Cow<'a, [u8]> {
532 let mut rng = testing_rng();
533 let tls_cert = TlsKeyAndCert::create(&mut rng, SystemTime::get(), issuer, subject).unwrap();
534 Cow::Owned(tls_cert.certificates_der()[0].to_vec())
535 }
536
537 pub(crate) struct DummyChanProvider<R> {
538 runtime: R,
540 outbound: Arc<Mutex<Option<DummyChan>>>,
542 }
543
544 impl<R: Runtime> DummyChanProvider<R> {
545 pub(crate) fn new(runtime: R, outbound: Arc<Mutex<Option<DummyChan>>>) -> Self {
546 Self { runtime, outbound }
547 }
548
549 pub(crate) fn new_without_chan(runtime: R) -> Self {
551 Self {
552 runtime,
553 outbound: Arc::new(Mutex::new(None)),
554 }
555 }
556 }
557
558 impl<R: Runtime> ChannelProvider for DummyChanProvider<R> {
559 type BuildSpec = OwnedChanTarget;
560
561 fn get_or_launch(
562 self: Arc<Self>,
563 _reactor_id: UniqId,
564 _target: Self::BuildSpec,
565 tx: OutboundChanSender,
566 ) -> crate::Result<()> {
567 let dummy_chan = working_dummy_channel(&self.runtime);
568 let chan = Arc::clone(&dummy_chan.channel);
569 {
570 let mut lock = self.outbound.lock().unwrap();
571 assert!(lock.is_none());
572 *lock = Some(dummy_chan);
573 }
574
575 tx.send(Ok(chan));
576
577 Ok(())
578 }
579 }
580
581 pub(crate) struct DummyChan {
583 pub(crate) rx: Receiver<AnyChanCell>,
585 pub(crate) tx: Sender<CodecResult>,
587 pub(crate) channel: Arc<Channel>,
590 }
591
592 pub(crate) fn working_dummy_channel<R: Runtime>(rt: &R) -> DummyChan {
593 let (channel, chan_reactor, rx, tx) = new_reactor(rt.clone());
594 rt.spawn(async {
595 let _ignore = chan_reactor.run().await;
596 })
597 .unwrap();
598
599 DummyChan { tx, rx, channel }
600 }
601
602 pub(crate) fn fake_auth_material() -> Arc<RelayChannelAuthMaterial> {
605 const KEY_DURATION_2DAYS: Duration = Duration::from_secs(2 * 24 * 60 * 60);
606 const KEY_DURATION_30DAYS: Duration = Duration::from_secs(30 * 24 * 60 * 60);
607
608 static AUTH: OnceLock<Arc<RelayChannelAuthMaterial>> = OnceLock::new();
609 AUTH.get_or_init(|| {
610 let now = SystemTime::get();
611 let mut rng = tor_llcrypto::rng::CautiousRng;
613
614 let issuer_hostname = "issuer.test.nowar.net";
615 let subject_hostname = "subject.test.nowar.net";
616
617 let kp_relayid_rsa = RelayIdentityRsaKeypair::generate(&mut rng).unwrap();
619
620 let kp_relayid_ed = RelayIdentityKeypair::generate(&mut rng).unwrap();
622 let kp_relaysign_ed = RelaySigningKeypair::generate(&mut rng).unwrap();
623 let kp_link_ed = RelayLinkSigningKeypair::generate(&mut rng).unwrap();
624
625 let tls_key_and_cert =
627 TlsKeyAndCert::create(&mut rng, now, issuer_hostname, subject_hostname).unwrap();
628
629 let cert_id_sign_ed =
631 gen_signing_cert(&kp_relayid_ed, &kp_relaysign_ed, now + KEY_DURATION_30DAYS)
632 .unwrap();
633 let cert_sign_link_auth_ed =
634 gen_link_cert(&kp_relaysign_ed, &kp_link_ed, now + KEY_DURATION_2DAYS).unwrap();
635 let cert_sign_tls_ed = gen_tls_cert(
636 &kp_relaysign_ed,
637 *tls_key_and_cert.link_cert_sha256(),
638 now + KEY_DURATION_2DAYS,
639 )
640 .unwrap();
641
642 let cert_id_rsa = tor_cert::rsa::EncodedRsaCrosscert::encode_and_sign(
644 kp_relayid_rsa.keypair(),
645 &kp_relayid_ed.to_ed25519_id(),
646 now + KEY_DURATION_2DAYS,
647 )
648 .unwrap();
649
650 let cert_id_x509_rsa = tor_cert::x509::create_legacy_rsa_id_cert(
652 &mut rng,
653 now,
654 issuer_hostname,
655 kp_relayid_rsa.keypair(),
656 )
657 .unwrap();
658
659 Arc::new(RelayChannelAuthMaterial::new(
660 &kp_relayid_rsa.public().into(),
661 kp_relayid_ed.to_ed25519_id(),
662 kp_link_ed,
663 cert_id_sign_ed.to_encodable_cert(),
664 cert_sign_tls_ed,
665 cert_sign_link_auth_ed.to_encodable_cert(),
666 cert_id_x509_rsa,
667 cert_id_rsa,
668 tls_key_and_cert,
669 ))
670 })
671 .clone()
672 }
673}