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