1use super::{Coverage, CoverageError};
4use crate::pki::CheckedPath;
5use crate::source::{Location, Query, ScopeError, Snapshot};
6use crate::timestamp::{Purpose, Verified};
7use core::hash::Hash;
8use core::marker::PhantomData;
9use structured_asn1::memory::{HashWork, MemoryError, OwnedMap, OwnedVec, Work};
10use structured_pkix::{Certificate, crl::CertificateList, ocsp::BasicResponse};
11
12#[derive(Clone, Copy, PartialEq, Eq, Hash)]
13pub(super) enum Kind {
14 Certificate,
15 Crl,
16 Basic,
17}
18
19#[derive(Clone, Copy, PartialEq, Eq, Hash)]
22pub struct ArtifactKey<'source> {
23 pub(super) kind: Kind,
24 pub(super) bytes: &'source [u8],
25}
26
27impl HashWork for ArtifactKey<'_> {
28 fn hash_work(&self) -> Result<u64, MemoryError> {
29 u64::try_from(self.bytes.len())
30 .map_err(|_| MemoryError::WorkExceeded)?
31 .checked_add(2)
32 .ok_or(MemoryError::WorkExceeded)
33 }
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39pub struct CarriedOrigin {
40 pub token: usize,
42 pub choice: usize,
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49pub enum ArtifactSource {
50 Material(usize),
52 TokenCertificate {
54 token: usize,
56 certificate: usize,
58 },
59 TokenRevocation(CarriedOrigin),
61}
62
63#[derive(Debug, Clone, Copy)]
66pub struct Occurrence<N, D, G, P> {
67 source: ArtifactSource,
68 location: Location<N, D, G>,
69 placement: P,
70 embedded_certificate: Option<usize>,
71}
72
73impl<N: Copy, D: Copy, G: Copy, P: Copy> Occurrence<N, D, G, P> {
74 #[must_use]
76 pub fn new(source: ArtifactSource, location: Location<N, D, G>, placement: P) -> Self {
77 Self {
78 source,
79 location,
80 placement,
81 embedded_certificate: None,
82 }
83 }
84 #[must_use]
87 pub fn source(&self) -> ArtifactSource {
88 self.source
89 }
90 #[must_use]
92 pub fn location(&self) -> Location<N, D, G> {
93 self.location
94 }
95 #[must_use]
97 pub fn placement(&self) -> P {
98 self.placement
99 }
100 #[must_use]
103 pub fn embedded_certificate(&self) -> Option<usize> {
104 self.embedded_certificate
105 }
106}
107
108struct Entry<N, D, G, P> {
109 value: Occurrence<N, D, G, P>,
110 next: Option<usize>,
111}
112
113pub struct Index<'source, N, D, G, P, O, W: Work, I> {
123 snapshot: Snapshot<D, G>,
124 signature: N,
125 keys: OwnedMap<ArtifactKey<'source>, (usize, usize), W>,
126 entries: OwnedVec<Entry<N, D, G, P>, W>,
127 open: &'source [O],
128 issuer: PhantomData<I>,
129}
130
131#[derive(Debug, Clone, Copy, PartialEq, Eq)]
133pub enum IndexError<N> {
134 Scope(ScopeError<N>),
136 Foreign {
138 signature: N,
140 },
141 Resource {
143 signature: N,
145 cause: MemoryError,
147 },
148}
149
150#[derive(Debug, Clone, Copy)]
153pub enum ArtifactRef<'view, 'source> {
154 Certificate(&'view Certificate<'source>),
156 Crl(&'view CertificateList<'source>),
158 Ocsp(&'view BasicResponse<'source>),
161}
162
163impl<'source> ArtifactRef<'_, 'source> {
164 #[must_use]
166 pub fn identity(self) -> ArtifactKey<'source> {
167 match self {
168 Self::Certificate(value) => ArtifactKey {
169 kind: Kind::Certificate,
170 bytes: value.as_bytes(),
171 },
172 Self::Crl(value) => ArtifactKey {
173 kind: Kind::Crl,
174 bytes: value.as_bytes(),
175 },
176 Self::Ocsp(value) => ArtifactKey {
177 kind: Kind::Basic,
178 bytes: value.as_bytes(),
179 },
180 }
181 }
182}
183
184#[derive(Debug)]
186pub enum Archived<N, D, G, P> {
187 Missing,
189 Uncovered,
192 Present(Occurrence<N, D, G, P>),
194}
195
196#[derive(Debug, Clone, Copy, PartialEq, Eq)]
198pub enum PathCertificate {
199 Anchor,
202 Member(usize),
204}
205
206#[derive(Debug)]
208pub struct ArchivedCertificate<N, D, G, P> {
209 pub role: PathCertificate,
211 pub availability: Archived<N, D, G, P>,
213}
214
215pub struct PathCertificates<'path, 'document, N, D, G, P> {
219 path: &'path CheckedPath<'document>,
220 archive: Location<N, D, G>,
221 entries: OwnedVec<ArchivedCertificate<N, D, G, P>>,
222 all_covered: bool,
223}
224
225impl<'path, 'document, N: Copy, D: Copy, G: Copy, P>
226 PathCertificates<'path, 'document, N, D, G, P>
227{
228 #[must_use]
230 pub fn path(&self) -> &'path CheckedPath<'document> {
231 self.path
232 }
233 #[must_use]
235 pub fn archive(&self) -> Location<N, D, G> {
236 self.archive
237 }
238 #[must_use]
240 pub fn entries(&self) -> &[ArchivedCertificate<N, D, G, P>] {
241 &self.entries
242 }
243 #[must_use]
246 pub fn all_certificates_covered(&self) -> bool {
247 self.all_covered
248 }
249}
250
251#[derive(Debug, Clone, Copy, PartialEq, Eq)]
253pub enum ArchiveError<N> {
254 Index(IndexError<N>),
256 Coverage(CoverageError<N>),
258 NotArchive {
260 property: N,
262 },
263}
264
265impl<'source, N: Copy + Eq, D: Copy + Eq, G: Copy + Eq, P: Copy, O, W: Work, I>
266 Index<'source, N, D, G, P, O, W, I>
267{
268 pub fn new<Q: Query<Id = N, Document = D, Generation = G, Work = W>>(
274 _issuer: I,
275 signature: N,
276 open: &'source [O],
277 query: &Q,
278 ) -> Result<Self, IndexError<N>> {
279 query.admit(signature, 1).map_err(IndexError::Scope)?;
280 let execution = query.execution();
281 Ok(Self {
282 snapshot: query.snapshot(),
283 signature,
284 keys: execution.map(),
285 entries: execution.vector(),
286 open,
287 issuer: PhantomData,
288 })
289 }
290
291 pub fn insert<Q: Query<Id = N, Document = D, Generation = G, Work = W>>(
299 &mut self,
300 _issuer: I,
301 artifact: ArtifactRef<'_, 'source>,
302 occurrence: Occurrence<N, D, G, P>,
303 query: &Q,
304 ) -> Result<(), IndexError<N>> {
305 if occurrence.location.snapshot != self.snapshot || query.snapshot() != self.snapshot {
308 return Err(IndexError::Foreign {
309 signature: self.signature,
310 });
311 }
312 self.insert_key(artifact.identity(), occurrence, query)?;
313 if let ArtifactRef::Ocsp(response) = artifact {
314 for certificate in 0..response.certificates().len() {
315 self.admit(query)?;
316 self.insert_key(
317 ArtifactKey {
318 kind: Kind::Certificate,
319 bytes: response.certificates()[certificate].as_bytes(),
320 },
321 Occurrence {
322 embedded_certificate: Some(certificate),
323 ..occurrence
324 },
325 query,
326 )?;
327 }
328 }
329 Ok(())
330 }
331
332 #[must_use]
334 pub fn open(&self) -> &'source [O] {
335 self.open
336 }
337
338 #[must_use]
340 pub fn signature(&self) -> N {
341 self.signature
342 }
343
344 #[must_use]
346 pub fn snapshot(&self) -> Snapshot<D, G> {
347 self.snapshot
348 }
349
350 pub fn certificate<'view, 'query, Q: Query<Id = N, Document = D, Generation = G>>(
353 &'view self,
354 value: &Certificate<'_>,
355 query: &'query Q,
356 ) -> Lookup<'view, 'query, 'source, N, D, G, P, O, W, Q, I> {
357 self.find(Kind::Certificate, value.as_bytes(), query)
358 }
359 pub fn crl<'view, 'query, Q: Query<Id = N, Document = D, Generation = G>>(
362 &'view self,
363 value: &CertificateList<'_>,
364 query: &'query Q,
365 ) -> Lookup<'view, 'query, 'source, N, D, G, P, O, W, Q, I> {
366 self.find(Kind::Crl, value.as_bytes(), query)
367 }
368 pub fn ocsp<'view, 'query, Q: Query<Id = N, Document = D, Generation = G>>(
371 &'view self,
372 value: &BasicResponse<'_>,
373 query: &'query Q,
374 ) -> Lookup<'view, 'query, 'source, N, D, G, P, O, W, Q, I> {
375 self.find(Kind::Basic, value.as_bytes(), query)
376 }
377
378 pub fn artifact<'view, 'query, Q: Query<Id = N, Document = D, Generation = G>>(
380 &'view self,
381 artifact: ArtifactRef<'_, '_>,
382 query: &'query Q,
383 ) -> Lookup<'view, 'query, 'source, N, D, G, P, O, W, Q, I> {
384 let key = artifact.identity();
385 self.find(key.kind, key.bytes, query)
386 }
387
388 pub fn require_signature<Q: Query<Id = N, Document = D, Generation = G>>(
390 &self,
391 signature: N,
392 query: &Q,
393 ) -> Result<(), IndexError<N>> {
394 self.admit(query)?;
395 let same =
396 query
397 .equal(self.signature, signature)
398 .map_err(|cause| IndexError::Resource {
399 signature: self.signature,
400 cause,
401 })?;
402 if !same {
403 return Err(IndexError::Foreign { signature });
404 }
405 Ok(())
406 }
407
408 pub fn archived<Q: Query<Id = N, Document = D, Generation = G>, C: Work>(
420 &self,
421 artifact: ArtifactRef<'_, '_>,
422 coverage: &Coverage<N, D, G, C, I>,
423 evidence: &Verified<N, D, G, I>,
424 query: &Q,
425 ) -> Result<Archived<N, D, G, P>, ArchiveError<N>>
426 where
427 N: HashWork,
428 {
429 if evidence.purpose() != Purpose::Archive {
430 return Err(ArchiveError::NotArchive {
431 property: evidence.property(),
432 });
433 }
434 if evidence.token().snapshot != self.snapshot {
436 return Err(ArchiveError::Index(IndexError::Foreign {
437 signature: self.signature,
438 }));
439 }
440 self.require_signature(evidence.signature(), query)
441 .map_err(ArchiveError::Index)?;
442 coverage
443 .require_evidence(evidence, evidence.property(), query)
444 .map_err(ArchiveError::Coverage)?;
445 let key = artifact.identity();
446 let copies = self
447 .find(key.kind, key.bytes, query)
448 .map_err(ArchiveError::Index)?;
449 let mut found = false;
450 for copy in copies {
451 let copy = copy.map_err(ArchiveError::Index)?;
452 found = true;
453 if coverage
456 .selects(copy.location.node, query)
457 .map_err(ArchiveError::Coverage)?
458 {
459 return Ok(Archived::Present(copy));
460 }
461 }
462 Ok(if found {
463 Archived::Uncovered
464 } else {
465 Archived::Missing
466 })
467 }
468
469 pub fn archived_path<'path, 'document, Q, C: Work>(
480 &self,
481 path: &'path CheckedPath<'document>,
482 coverage: &Coverage<N, D, G, C, I>,
483 evidence: &Verified<N, D, G, I>,
484 query: &Q,
485 ) -> Result<PathCertificates<'path, 'document, N, D, G, P>, ArchiveError<N>>
486 where
487 N: HashWork,
488 Q: Query<Id = N, Document = D, Generation = G>,
489 {
490 query
491 .admit(self.signature, 1)
492 .map_err(|cause| ArchiveError::Index(IndexError::Scope(cause)))?;
493 let mut entries = query.execution().vector();
494 let mut all_covered = true;
495 let mut record = |certificate, role| {
496 let availability = self.archived(
497 ArtifactRef::Certificate(certificate),
498 coverage,
499 evidence,
500 query,
501 )?;
502 if !matches!(availability, Archived::Present(_)) {
503 all_covered = false;
504 }
505 entries
506 .try_push(ArchivedCertificate { role, availability })
507 .map_err(|cause| {
508 ArchiveError::Index(IndexError::Resource {
509 signature: self.signature,
510 cause,
511 })
512 })
513 };
514 if let Some(certificate) = path.anchor().certificate() {
515 record(certificate, PathCertificate::Anchor)?;
516 }
517 for (ordinal, member) in path.members().iter().enumerate() {
518 self.admit(query).map_err(ArchiveError::Index)?;
519 record(member.certificate(), PathCertificate::Member(ordinal))?;
520 }
521 Ok(PathCertificates {
522 path,
523 archive: evidence.token(),
524 entries: entries.into_owned(),
525 all_covered,
526 })
527 }
528
529 pub fn admit<Q: Query<Id = N, Document = D, Generation = G>>(
531 &self,
532 query: &Q,
533 ) -> Result<(), IndexError<N>> {
534 if self.snapshot != query.snapshot() {
535 return Err(IndexError::Foreign {
536 signature: self.signature,
537 });
538 }
539 query.admit(self.signature, 2).map_err(IndexError::Scope)
540 }
541
542 fn insert_key<Q: Query<Id = N, Document = D, Generation = G, Work = W>>(
543 &mut self,
544 key: ArtifactKey<'source>,
545 value: Occurrence<N, D, G, P>,
546 query: &Q,
547 ) -> Result<(), IndexError<N>> {
548 query.admit(self.signature, 1).map_err(IndexError::Scope)?;
549 let resource = |cause| IndexError::Resource {
550 signature: self.signature,
551 cause,
552 };
553 let previous = self
554 .keys
555 .get(&key, query.execution())
556 .map(Option::<&(usize, usize)>::copied)
557 .map_err(resource)?;
558 let next = self.entries.len();
559 self.entries
560 .try_push(Entry { value, next: None })
561 .map_err(resource)?;
562 let head = previous.map_or(next, |(head, _)| head);
563 self.keys.try_insert(key, (head, next)).map_err(resource)?;
564 if let Some((_, tail)) = previous {
565 self.entries[tail].next = Some(next);
566 }
567 Ok(())
568 }
569
570 fn find<'view, 'query, Q: Query<Id = N, Document = D, Generation = G>>(
571 &'view self,
572 kind: Kind,
573 bytes: &[u8],
574 query: &'query Q,
575 ) -> Lookup<'view, 'query, 'source, N, D, G, P, O, W, Q, I> {
576 self.admit(query)?;
577 query.admit(self.signature, 1).map_err(IndexError::Scope)?;
578 let next = self
579 .keys
580 .get(&ArtifactKey { kind, bytes }, query.execution())
581 .map(|value| value.map(|&(head, _)| head))
582 .map_err(|cause| IndexError::Resource {
583 signature: self.signature,
584 cause,
585 })?;
586 Ok(Occurrences {
587 index: self,
588 query,
589 next,
590 })
591 }
592}
593
594pub type Lookup<'view, 'query, 'source, N, D, G, P, O, W, Q, I> =
596 Result<Occurrences<'view, 'query, 'source, N, D, G, P, O, W, Q, I>, IndexError<N>>;
597
598pub struct Occurrences<'view, 'query, 'source, N, D, G, P, O, W: Work, Q, I> {
602 index: &'view Index<'source, N, D, G, P, O, W, I>,
603 query: &'query Q,
604 next: Option<usize>,
605}
606
607impl<N: Copy + Eq, D: Copy + Eq, G: Copy + Eq, P: Copy, O, W: Work, Q, I> Iterator
608 for Occurrences<'_, '_, '_, N, D, G, P, O, W, Q, I>
609where
610 Q: Query<Id = N, Document = D, Generation = G>,
611{
612 type Item = Result<Occurrence<N, D, G, P>, IndexError<N>>;
613 fn next(&mut self) -> Option<Self::Item> {
614 let next = self.next.take()?;
615 if let Err(error) = self.index.admit(self.query) {
616 return Some(Err(error));
617 }
618 let entry = &self.index.entries[next];
619 self.next = entry.next;
620 Some(Ok(entry.value))
621 }
622}
623
624impl<N: Copy + Eq, D: Copy + Eq, G: Copy + Eq, P: Copy, O, W: Work, Q, I> core::iter::FusedIterator
625 for Occurrences<'_, '_, '_, N, D, G, P, O, W, Q, I>
626where
627 Q: Query<Id = N, Document = D, Generation = G>,
628{
629}