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
73type OccurrenceItem<N, D, G, P> = Result<Occurrence<N, D, G, P>, IndexError<N>>;
75
76impl<N: Copy, D: Copy, G: Copy, P: Copy> Occurrence<N, D, G, P> {
77 #[must_use]
79 pub fn new(source: ArtifactSource, location: Location<N, D, G>, placement: P) -> Self {
80 Self {
81 source,
82 location,
83 placement,
84 embedded_certificate: None,
85 }
86 }
87 #[must_use]
90 pub fn source(&self) -> ArtifactSource {
91 self.source
92 }
93 #[must_use]
95 pub fn location(&self) -> Location<N, D, G> {
96 self.location
97 }
98 #[must_use]
100 pub fn placement(&self) -> P {
101 self.placement
102 }
103 #[must_use]
106 pub fn embedded_certificate(&self) -> Option<usize> {
107 self.embedded_certificate
108 }
109}
110
111struct Entry<N, D, G, P> {
112 value: Occurrence<N, D, G, P>,
113 next: Option<usize>,
114}
115
116pub struct Index<'source, N, D, G, P, O, W: Work, I> {
126 snapshot: Snapshot<D, G>,
127 signature: N,
128 keys: OwnedMap<ArtifactKey<'source>, (usize, usize), W>,
129 entries: OwnedVec<Entry<N, D, G, P>, W>,
130 open: &'source [O],
131 issuer: PhantomData<I>,
132}
133
134#[derive(Debug, Clone, Copy, PartialEq, Eq)]
136pub enum IndexError<N> {
137 Scope(ScopeError<N>),
139 Foreign {
141 signature: N,
143 },
144 Resource {
146 signature: N,
148 cause: MemoryError,
150 },
151}
152
153#[derive(Debug, Clone, Copy)]
156pub enum ArtifactRef<'view, 'source> {
157 Certificate(&'view Certificate<'source>),
159 Crl(&'view CertificateList<'source>),
161 Ocsp(&'view BasicResponse<'source>),
166}
167
168impl<'source> ArtifactRef<'_, 'source> {
169 #[must_use]
171 pub fn identity(self) -> ArtifactKey<'source> {
172 match self {
173 Self::Certificate(value) => ArtifactKey {
174 kind: Kind::Certificate,
175 bytes: value.as_bytes(),
176 },
177 Self::Crl(value) => ArtifactKey {
178 kind: Kind::Crl,
179 bytes: value.as_bytes(),
180 },
181 Self::Ocsp(value) => ArtifactKey {
182 kind: Kind::Basic,
183 bytes: value.as_bytes(),
184 },
185 }
186 }
187}
188
189#[derive(Debug)]
191pub enum Archived<N, D, G, P> {
192 Missing,
194 Uncovered,
197 Present(Occurrence<N, D, G, P>),
199}
200
201#[derive(Debug, Clone, Copy, PartialEq, Eq)]
203pub enum PathCertificate {
204 Anchor,
207 Member(usize),
209}
210
211#[derive(Debug)]
213pub struct ArchivedCertificate<N, D, G, P> {
214 pub role: PathCertificate,
216 pub availability: Archived<N, D, G, P>,
218}
219
220pub struct PathCertificates<'path, 'document, N, D, G, P> {
224 path: &'path CheckedPath<'document>,
225 archive: Location<N, D, G>,
226 entries: OwnedVec<ArchivedCertificate<N, D, G, P>>,
227 all_covered: bool,
228}
229
230impl<'path, 'document, N: Copy, D: Copy, G: Copy, P>
231 PathCertificates<'path, 'document, N, D, G, P>
232{
233 #[must_use]
235 pub fn path(&self) -> &'path CheckedPath<'document> {
236 self.path
237 }
238 #[must_use]
240 pub fn archive(&self) -> Location<N, D, G> {
241 self.archive
242 }
243 #[must_use]
245 pub fn entries(&self) -> &[ArchivedCertificate<N, D, G, P>] {
246 &self.entries
247 }
248 #[must_use]
251 pub fn all_certificates_covered(&self) -> bool {
252 self.all_covered
253 }
254}
255
256#[derive(Debug, Clone, Copy, PartialEq, Eq)]
258pub enum ArchiveError<N> {
259 Index(IndexError<N>),
261 Coverage(CoverageError<N>),
263 NotArchive {
265 property: N,
267 },
268}
269
270impl<'source, N: Copy + Eq, D: Copy + Eq, G: Copy + Eq, P: Copy, O, W: Work, I>
271 Index<'source, N, D, G, P, O, W, I>
272{
273 pub fn new<Q: Query<Id = N, Document = D, Generation = G, Work = W>>(
279 _issuer: I,
280 signature: N,
281 open: &'source [O],
282 query: &Q,
283 ) -> Result<Self, IndexError<N>> {
284 query.admit(signature, 1).map_err(IndexError::Scope)?;
285 let execution = query.execution();
286 Ok(Self {
287 snapshot: query.snapshot(),
288 signature,
289 keys: execution.map(),
290 entries: execution.vector(),
291 open,
292 issuer: PhantomData,
293 })
294 }
295
296 pub fn insert<Q: Query<Id = N, Document = D, Generation = G, Work = W>>(
304 &mut self,
305 _issuer: I,
306 artifact: ArtifactRef<'_, 'source>,
307 occurrence: Occurrence<N, D, G, P>,
308 query: &Q,
309 ) -> Result<(), IndexError<N>> {
310 if occurrence.location.snapshot != self.snapshot || query.snapshot() != self.snapshot {
313 return Err(IndexError::Foreign {
314 signature: self.signature,
315 });
316 }
317 self.insert_key(artifact.identity(), occurrence, query)?;
318 if let ArtifactRef::Ocsp(response) = artifact {
319 for certificate in 0..response.certificates().len() {
320 self.admit(query)?;
321 self.insert_key(
322 ArtifactKey {
323 kind: Kind::Certificate,
324 bytes: response.certificates()[certificate].as_bytes(),
325 },
326 Occurrence {
327 embedded_certificate: Some(certificate),
328 ..occurrence
329 },
330 query,
331 )?;
332 }
333 }
334 Ok(())
335 }
336
337 #[must_use]
339 pub fn open(&self) -> &'source [O] {
340 self.open
341 }
342
343 pub fn all_occurrences<'view, 'query, Q>(
350 &'view self,
351 query: &'query Q,
352 ) -> Result<
353 impl Iterator<Item = OccurrenceItem<N, D, G, P>>
354 + use<'view, 'query, 'source, N, D, G, P, O, W, Q, I>,
355 IndexError<N>,
356 >
357 where
358 Q: Query<Id = N, Document = D, Generation = G>,
359 {
360 self.admit(query)?;
361 let mut next = if self.entries.is_empty() {
362 None
363 } else {
364 Some(0)
365 };
366 Ok(core::iter::from_fn(move || {
367 let ordinal = next.take()?;
368 if let Err(cause) = self.admit(query) {
369 return Some(Err(cause));
370 }
371 let value = self.entries[ordinal].value;
372 if ordinal + 1 < self.entries.len() {
373 next = Some(ordinal + 1);
374 }
375 Some(Ok(value))
376 }))
377 }
378
379 #[must_use]
381 pub fn signature(&self) -> N {
382 self.signature
383 }
384
385 #[must_use]
387 pub fn snapshot(&self) -> Snapshot<D, G> {
388 self.snapshot
389 }
390
391 pub fn certificate<'view, 'query, Q: Query<Id = N, Document = D, Generation = G>>(
394 &'view self,
395 value: &Certificate<'_>,
396 query: &'query Q,
397 ) -> Lookup<'view, 'query, 'source, N, D, G, P, O, W, Q, I> {
398 self.find(Kind::Certificate, value.as_bytes(), query)
399 }
400 pub fn crl<'view, 'query, Q: Query<Id = N, Document = D, Generation = G>>(
403 &'view self,
404 value: &CertificateList<'_>,
405 query: &'query Q,
406 ) -> Lookup<'view, 'query, 'source, N, D, G, P, O, W, Q, I> {
407 self.find(Kind::Crl, value.as_bytes(), query)
408 }
409 pub fn ocsp<'view, 'query, Q: Query<Id = N, Document = D, Generation = G>>(
412 &'view self,
413 value: &BasicResponse<'_>,
414 query: &'query Q,
415 ) -> Lookup<'view, 'query, 'source, N, D, G, P, O, W, Q, I> {
416 self.find(Kind::Basic, value.as_bytes(), query)
417 }
418
419 pub fn artifact<'view, 'query, Q: Query<Id = N, Document = D, Generation = G>>(
421 &'view self,
422 artifact: ArtifactRef<'_, '_>,
423 query: &'query Q,
424 ) -> Lookup<'view, 'query, 'source, N, D, G, P, O, W, Q, I> {
425 let key = artifact.identity();
426 self.find(key.kind, key.bytes, query)
427 }
428
429 pub fn require_signature<Q: Query<Id = N, Document = D, Generation = G>>(
431 &self,
432 signature: N,
433 query: &Q,
434 ) -> Result<(), IndexError<N>> {
435 self.admit(query)?;
436 let same =
437 query
438 .equal(self.signature, signature)
439 .map_err(|cause| IndexError::Resource {
440 signature: self.signature,
441 cause,
442 })?;
443 if !same {
444 return Err(IndexError::Foreign { signature });
445 }
446 Ok(())
447 }
448
449 pub fn archived<Q: Query<Id = N, Document = D, Generation = G>, C: Work>(
461 &self,
462 artifact: ArtifactRef<'_, '_>,
463 coverage: &Coverage<N, D, G, C, I>,
464 evidence: &Verified<N, D, G, I>,
465 query: &Q,
466 ) -> Result<Archived<N, D, G, P>, ArchiveError<N>>
467 where
468 N: HashWork,
469 {
470 if evidence.purpose() != Purpose::Archive {
471 return Err(ArchiveError::NotArchive {
472 property: evidence.property(),
473 });
474 }
475 if evidence.token().snapshot != self.snapshot {
477 return Err(ArchiveError::Index(IndexError::Foreign {
478 signature: self.signature,
479 }));
480 }
481 self.require_signature(evidence.signature(), query)
482 .map_err(ArchiveError::Index)?;
483 coverage
484 .require_evidence(evidence, evidence.property(), query)
485 .map_err(ArchiveError::Coverage)?;
486 let key = artifact.identity();
487 let copies = self
488 .find(key.kind, key.bytes, query)
489 .map_err(ArchiveError::Index)?;
490 let mut found = false;
491 for copy in copies {
492 let copy = copy.map_err(ArchiveError::Index)?;
493 found = true;
494 if coverage
497 .selects(copy.location.node, query)
498 .map_err(ArchiveError::Coverage)?
499 {
500 return Ok(Archived::Present(copy));
501 }
502 }
503 Ok(if found {
504 Archived::Uncovered
505 } else {
506 Archived::Missing
507 })
508 }
509
510 pub fn archived_path<'path, 'document, Q, C: Work>(
521 &self,
522 path: &'path CheckedPath<'document>,
523 coverage: &Coverage<N, D, G, C, I>,
524 evidence: &Verified<N, D, G, I>,
525 query: &Q,
526 ) -> Result<PathCertificates<'path, 'document, N, D, G, P>, ArchiveError<N>>
527 where
528 N: HashWork,
529 Q: Query<Id = N, Document = D, Generation = G>,
530 {
531 query
532 .admit(self.signature, 1)
533 .map_err(|cause| ArchiveError::Index(IndexError::Scope(cause)))?;
534 let mut entries = query.execution().vector();
535 let mut all_covered = true;
536 let mut record = |certificate, role| {
537 let availability = self.archived(
538 ArtifactRef::Certificate(certificate),
539 coverage,
540 evidence,
541 query,
542 )?;
543 if !matches!(availability, Archived::Present(_)) {
544 all_covered = false;
545 }
546 entries
547 .try_push(ArchivedCertificate { role, availability })
548 .map_err(|cause| {
549 ArchiveError::Index(IndexError::Resource {
550 signature: self.signature,
551 cause,
552 })
553 })
554 };
555 if let Some(certificate) = path.anchor().certificate() {
556 record(certificate, PathCertificate::Anchor)?;
557 }
558 for (ordinal, member) in path.members().iter().enumerate() {
559 self.admit(query).map_err(ArchiveError::Index)?;
560 record(member.certificate(), PathCertificate::Member(ordinal))?;
561 }
562 Ok(PathCertificates {
563 path,
564 archive: evidence.token(),
565 entries: entries.into_owned(),
566 all_covered,
567 })
568 }
569
570 pub fn admit<Q: Query<Id = N, Document = D, Generation = G>>(
572 &self,
573 query: &Q,
574 ) -> Result<(), IndexError<N>> {
575 if self.snapshot != query.snapshot() {
576 return Err(IndexError::Foreign {
577 signature: self.signature,
578 });
579 }
580 query.admit(self.signature, 2).map_err(IndexError::Scope)
581 }
582
583 fn insert_key<Q: Query<Id = N, Document = D, Generation = G, Work = W>>(
584 &mut self,
585 key: ArtifactKey<'source>,
586 value: Occurrence<N, D, G, P>,
587 query: &Q,
588 ) -> Result<(), IndexError<N>> {
589 query.admit(self.signature, 1).map_err(IndexError::Scope)?;
590 let resource = |cause| IndexError::Resource {
591 signature: self.signature,
592 cause,
593 };
594 let previous = self
595 .keys
596 .get(&key, query.execution())
597 .map(Option::<&(usize, usize)>::copied)
598 .map_err(resource)?;
599 let next = self.entries.len();
600 self.entries
601 .try_push(Entry { value, next: None })
602 .map_err(resource)?;
603 let head = previous.map_or(next, |(head, _)| head);
604 self.keys.try_insert(key, (head, next)).map_err(resource)?;
605 if let Some((_, tail)) = previous {
606 self.entries[tail].next = Some(next);
607 }
608 Ok(())
609 }
610
611 fn find<'view, 'query, Q: Query<Id = N, Document = D, Generation = G>>(
612 &'view self,
613 kind: Kind,
614 bytes: &[u8],
615 query: &'query Q,
616 ) -> Lookup<'view, 'query, 'source, N, D, G, P, O, W, Q, I> {
617 self.admit(query)?;
618 query.admit(self.signature, 1).map_err(IndexError::Scope)?;
619 let next = self
620 .keys
621 .get(&ArtifactKey { kind, bytes }, query.execution())
622 .map(|value| value.map(|&(head, _)| head))
623 .map_err(|cause| IndexError::Resource {
624 signature: self.signature,
625 cause,
626 })?;
627 Ok(Occurrences {
628 index: self,
629 query,
630 next,
631 })
632 }
633}
634
635pub type Lookup<'view, 'query, 'source, N, D, G, P, O, W, Q, I> =
637 Result<Occurrences<'view, 'query, 'source, N, D, G, P, O, W, Q, I>, IndexError<N>>;
638
639pub struct Occurrences<'view, 'query, 'source, N, D, G, P, O, W: Work, Q, I> {
643 index: &'view Index<'source, N, D, G, P, O, W, I>,
644 query: &'query Q,
645 next: Option<usize>,
646}
647
648impl<N: Copy + Eq, D: Copy + Eq, G: Copy + Eq, P: Copy, O, W: Work, Q, I> Iterator
649 for Occurrences<'_, '_, '_, N, D, G, P, O, W, Q, I>
650where
651 Q: Query<Id = N, Document = D, Generation = G>,
652{
653 type Item = Result<Occurrence<N, D, G, P>, IndexError<N>>;
654 fn next(&mut self) -> Option<Self::Item> {
655 let next = self.next.take()?;
656 if let Err(error) = self.index.admit(self.query) {
657 return Some(Err(error));
658 }
659 let entry = &self.index.entries[next];
660 self.next = entry.next;
661 Some(Ok(entry.value))
662 }
663}
664
665impl<N: Copy + Eq, D: Copy + Eq, G: Copy + Eq, P: Copy, O, W: Work, Q, I> core::iter::FusedIterator
666 for Occurrences<'_, '_, '_, N, D, G, P, O, W, Q, I>
667where
668 Q: Query<Id = N, Document = D, Generation = G>,
669{
670}