tor_netdoc/parse2/poc/netstatus/
flavoured.rs1use super::super::*;
15
16const TOPLEVEL_DOCTYPE_FOR_ERROR: &str =
18 ns_expr!("NetworkStatusVote", "NetworkStatusNs", "NetworkStatusMd",);
19
20pub type Router = ns_type!(
22 crate::doc::netstatus::VoteRouterStatus,
23 crate::doc::netstatus::PlainRouterStatus,
24 crate::doc::netstatus::MdRouterStatus,
25);
26
27#[derive(Deftly, Clone, Debug)]
32#[derive_deftly(NetdocParseableUnverified)]
33#[deftly(netdoc(doctype_for_error = TOPLEVEL_DOCTYPE_FOR_ERROR))]
34#[non_exhaustive]
35pub struct NetworkStatus {
36 pub network_status_version: (NdaNetworkStatusVersion, NdaNetworkStatusVersionFlavour),
38
39 pub vote_status: NdiVoteStatus,
41
42 pub published: ns_type!((NdaSystemTimeDeprecatedSyntax,), Option<Void>,),
44
45 pub valid_after: (NdaSystemTimeDeprecatedSyntax,),
47
48 pub valid_until: (NdaSystemTimeDeprecatedSyntax,),
50
51 pub voting_delay: NdiVotingDelay,
53
54 #[deftly(netdoc(default))]
56 pub params: NdiParams,
57
58 #[deftly(netdoc(subdoc))]
60 pub authority: NddAuthoritySection,
61
62 #[deftly(netdoc(subdoc))]
64 pub r: Vec<Router>,
65
66 #[deftly(netdoc(subdoc))]
68 pub directory_footer: Option<NddDirectoryFooter>,
69}
70
71#[derive(Deftly, Clone, Debug)]
73#[derive_deftly(NetdocParseableSignatures)]
74#[deftly(netdoc(signatures(hashes_accu = "DirectorySignaturesHashesAccu")))]
75#[non_exhaustive]
76pub struct NetworkStatusSignatures {
77 pub directory_signature: ns_type!(NdiDirectorySignature, Vec<NdiDirectorySignature>),
79}
80
81#[derive(Deftly, Clone, Debug, Hash, Eq, PartialEq)]
87#[derive_deftly(ItemValueParseable)]
88#[non_exhaustive]
89pub struct NdiVoteStatus {
90 pub status: NdaVoteStatus,
92}
93
94#[derive(Clone, Debug, Hash, Eq, PartialEq)]
96#[non_exhaustive]
97pub struct NdaVoteStatus {}
98
99#[derive(Clone, Debug, Hash, Eq, PartialEq)]
101#[non_exhaustive]
102pub struct NdaNetworkStatusVersionFlavour {}
103
104const NDA_NETWORK_STATUS_VERSION_FLAVOUR: Option<&str> = ns_expr!(None, None, Some("microdesc"));
106
107impl ItemArgumentParseable for NdaNetworkStatusVersionFlavour {
108 fn from_args<'s>(args: &mut ArgumentStream<'s>) -> Result<Self, AE> {
109 let exp: Option<&str> = NDA_NETWORK_STATUS_VERSION_FLAVOUR;
110 if let Some(exp) = exp {
111 let got = args.next().ok_or(AE::Missing)?;
112 if got != exp {
113 return Err(AE::Invalid);
114 };
115 } else {
116 args.reject_extra_args()?;
120 }
121 Ok(Self {})
122 }
123}
124
125const NDA_VOTE_STATUS: &str = ns_expr!("vote", "consensus", "consensus");
127
128impl FromStr for NdaVoteStatus {
129 type Err = InvalidNetworkStatusVoteStatus;
130 fn from_str(s: &str) -> Result<Self, InvalidNetworkStatusVoteStatus> {
131 if s == NDA_VOTE_STATUS {
132 Ok(Self {})
133 } else {
134 Err(InvalidNetworkStatusVoteStatus {})
135 }
136 }
137}
138
139impl Display for NdaVoteStatus {
140 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
141 Display::fmt(NDA_VOTE_STATUS, f)
142 }
143}
144
145impl NormalItemArgument for NdaVoteStatus {}
146
147#[derive(Deftly, Clone, Debug, Hash, Eq, PartialEq)]
149#[derive_deftly(ItemValueParseable)]
150#[non_exhaustive]
151pub struct NdiVotingDelay {
152 pub vote_seconds: u32,
154 pub dist_seconds: u32,
156}
157
158#[derive(Deftly, Clone, Debug)]
160#[derive_deftly(NetdocParseable)]
161#[non_exhaustive]
162pub struct NddDirectoryFooter {
163 pub directory_footer: (),
165}
166
167#[derive(Deftly, Clone, Debug)]
169#[derive_deftly(ItemValueParseable)]
170#[non_exhaustive]
171pub struct NdiAuthorityDirSource {
172 pub nickname: types::Nickname,
174 pub h_p_auth_id_rsa: types::Fingerprint,
176}
177
178ns_choose! { (
179 use VoteAuthoritySection as NddAuthoritySection;
180)(
181 use ConsensusAuthoritySection as NddAuthoritySection;
182)}
183
184ns_choose! { (
185 impl NetworkStatusUnverified {
186 pub fn verify_selfcert(
193 self,
194 now: SystemTime,
195 ) -> Result<(NetworkStatus, SignaturesData<NetworkStatusUnverified>), VF> {
196 let validity = *self.body.published.0 ..= *self.body.valid_until.0;
197 check_validity_time(now, validity)?;
198
199 let cert = self.body.parse_authcert()?.verify_selfcert(now)?;
200
201 netstatus::verify_general_timeless(
202 &self.sigs.hashes,
203 slice::from_ref(&self.sigs.sigs.directory_signature),
204 &[*cert.fingerprint],
205 &[&cert],
206 1,
207 )?;
208
209 Ok(self.unwrap_unverified())
210 }
211 }
212
213 impl NetworkStatus {
214 fn parse_authcert(&self) -> Result<crate::doc::authcert::AuthCertUnverified, EP> {
216 let cert_input = ParseInput::new(
217 self.authority.cert.as_str(),
218 "<embedded auth cert>",
219 );
220 parse_netdoc(&cert_input).map_err(|e| e.problem)
221 }
222
223 pub fn h_kp_auth_id_rsa(&self) -> pk::rsa::RsaIdentity {
233 *self.parse_authcert()
234 .expect("was verified already!")
238 .inspect_unverified()
239 .0
240 .fingerprint
241 }
242 }
243) (
244 impl NetworkStatusUnverified {
245 pub fn verify(
261 self,
262 now: SystemTime,
263 authorities: &[pk::rsa::RsaIdentity],
264 certs: &[&DirAuthKeyCert],
265 ) -> Result<(NetworkStatus, SignaturesData<NetworkStatusUnverified>), VF> {
266 let threshold = authorities.len() / 2 + 1; let validity_start = self.body.valid_after.0
268 .checked_sub(Duration::from_secs(self.body.voting_delay.dist_seconds.into()))
269 .ok_or(VF::Other)?;
270 check_validity_time(now, validity_start..= *self.body.valid_until.0)?;
271
272 netstatus::verify_general_timeless(
273 &self.sigs.hashes,
274 &self.sigs.sigs.directory_signature,
275 authorities,
276 certs,
277 threshold,
278 )?;
279
280 Ok(self.unwrap_unverified())
281 }
282 }
283)}