tor_hsservice/publish/
descriptor.rs1use super::*;
4use crate::config::OnionServiceConfigPublisherView;
5use tor_cell::chancell::msg::HandshakeType;
6use tor_llcrypto::rng::EntropicRng;
7
8#[allow(clippy::too_many_arguments)]
16pub(super) fn build_sign<
17 Rng: rand::Rng + CryptoRng,
18 KeyRng: rand::Rng + EntropicRng,
19 R: Runtime,
20>(
21 keymgr: &Arc<KeyMgr>,
22 pow_manager: &Arc<PowManager<R>>,
23 config: &Arc<OnionServiceConfigPublisherView>,
24 authorized_clients: Option<&RestrictedDiscoveryKeys>,
25 ipt_set: &IptSet,
26 period: TimePeriod,
27 revision_counter: RevisionCounter,
28 rng: &mut Rng,
29 key_rng: &mut KeyRng,
30 now: SystemTime,
31 max_hsdesc_len: usize,
32) -> Result<VersionedDescriptor, FatalError> {
33 const CREATE2_FORMATS: &[HandshakeType] = &[HandshakeType::NTOR];
37
38 const HS_DESC_CERT_LIFETIME_SEC: Duration = Duration::from_secs(54 * 60 * 60);
47
48 let intro_points = ipt_set
49 .ipts
50 .iter()
51 .map(|ipt_in_set| ipt_in_set.ipt.clone())
52 .collect::<Vec<_>>();
53
54 let nickname = &config.nickname;
55
56 let svc_key_spec = HsIdPublicKeySpecifier::new(nickname.clone());
57 let hsid = keymgr
58 .get::<HsIdKey>(&svc_key_spec)?
59 .ok_or_else(|| FatalError::MissingHsIdKeypair(nickname.clone()))?;
60
61 let keystore_selector = Default::default();
63 let blind_id_kp = read_blind_id_keypair(keymgr, nickname, period)?
64 .ok_or_else(|| internal!("hidden service offline mode not supported"))?;
65
66 let blind_id_key = HsBlindIdKey::from(&blind_id_kp);
67 let subcredential = hsid.compute_subcredential(&blind_id_key, period);
68
69 let hs_desc_sign_key_spec = DescSigningKeypairSpecifier::new(nickname.clone(), period);
70 let hs_desc_sign = keymgr.get_or_generate::<HsDescSigningKeypair>(
71 &hs_desc_sign_key_spec,
72 keystore_selector,
73 key_rng,
74 )?;
75
76 let auth_required = None;
78
79 let is_single_onion_service = false;
81
82 let intro_auth_key_cert_expiry = now + HS_DESC_CERT_LIFETIME_SEC;
85 let intro_enc_key_cert_expiry = now + HS_DESC_CERT_LIFETIME_SEC;
86 let hs_desc_sign_cert_expiry = now + HS_DESC_CERT_LIFETIME_SEC;
87
88 cfg_if::cfg_if! {
89 if #[cfg(feature = "restricted-discovery")] {
90 let auth_clients: Option<Vec<curve25519::PublicKey>> = authorized_clients
91 .as_ref()
92 .map(|authorized_clients| {
93 if authorized_clients.is_empty() {
94 return Err(internal!("restricted discovery enabled, but no authorized clients?!"));
95 }
96 let auth_clients = authorized_clients
97 .iter()
98 .map(|(nickname, key)| {
99 trace!("encrypting descriptor for client {nickname}");
100 (*key).clone().into()
101 })
102 .collect_vec();
103 Ok(auth_clients)
104 })
105 .transpose()?;
106 } else {
107 let auth_clients: Option<Vec<curve25519::PublicKey>> = None;
108 }
109 }
110
111 if let Some(ref auth_clients) = auth_clients {
112 debug!("Encrypting descriptor for {} clients", auth_clients.len());
113 }
114
115 let desc_signing_key_cert = create_desc_sign_key_cert(
116 &hs_desc_sign.as_ref().verifying_key(),
117 &blind_id_kp,
118 hs_desc_sign_cert_expiry,
119 )
120 .map_err(into_bad_api_usage!(
121 "failed to sign the descriptor signing key"
122 ))?;
123
124 let blind_id_kp = (&blind_id_kp).into();
125
126 let mut desc = HsDescBuilder::default()
127 .blinded_id(&blind_id_kp)
128 .hs_desc_sign(hs_desc_sign.as_ref())
129 .hs_desc_sign_cert(desc_signing_key_cert)
130 .create2_formats(CREATE2_FORMATS)
131 .auth_required(auth_required)
132 .is_single_onion_service(is_single_onion_service)
133 .intro_points(&intro_points[..])
134 .intro_auth_key_cert_expiry(intro_auth_key_cert_expiry)
135 .intro_enc_key_cert_expiry(intro_enc_key_cert_expiry)
136 .lifetime(((ipt_set.lifetime.as_secs() / 60) as u16).into())
137 .revision_counter(revision_counter)
138 .subcredential(subcredential)
139 .auth_clients(auth_clients.as_deref())
140 .max_generated_len(max_hsdesc_len);
141
142 cfg_if::cfg_if! {
143 if #[cfg(feature = "hs-pow-full")] {
144 let pow_params = pow_manager.get_pow_params(period, &mut rand::rng());
145 match pow_params {
146 Ok(ref pow_params) => {
147 if config.enable_pow {
148 desc = desc.pow_params(Some(pow_params));
149 }
150 },
151 Err(err) => {
152 warn!(?err, "Couldn't get PoW params");
153 }
154 }
155 }
156 }
157
158 let desc = desc.build_sign(rng).map_err(|e| match e {
159 tor_bytes::EncodeError::BadLengthValue => FatalError::HsDescTooLong,
160 e => into_internal!("failed to build descriptor")(e).into(),
161 })?;
162
163 Ok(VersionedDescriptor {
164 desc,
165 revision_counter,
166 })
167}
168
169#[derive(Copy, Clone, Debug, Default, PartialEq)]
171pub(super) enum DescriptorStatus {
172 #[default]
173 Dirty,
175 Clean,
177}
178
179#[derive(Clone)]
181pub(super) struct VersionedDescriptor {
182 pub(super) desc: String,
184 pub(super) revision_counter: RevisionCounter,
186}