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>),
163}
164
165impl<'source> ArtifactRef<'_, 'source> {
166 #[must_use]
168 pub fn identity(self) -> ArtifactKey<'source> {
169 match self {
170 Self::Certificate(value) => ArtifactKey {
171 kind: Kind::Certificate,
172 bytes: value.as_bytes(),
173 },
174 Self::Crl(value) => ArtifactKey {
175 kind: Kind::Crl,
176 bytes: value.as_bytes(),
177 },
178 Self::Ocsp(value) => ArtifactKey {
179 kind: Kind::Basic,
180 bytes: value.as_bytes(),
181 },
182 }
183 }
184}
185
186#[derive(Debug)]
188pub enum Archived<N, D, G, P> {
189 Missing,
191 Uncovered,
194 Present(Occurrence<N, D, G, P>),
196}
197
198#[derive(Debug, Clone, Copy, PartialEq, Eq)]
200pub enum PathCertificate {
201 Anchor,
204 Member(usize),
206}
207
208#[derive(Debug)]
210pub struct ArchivedCertificate<N, D, G, P> {
211 pub role: PathCertificate,
213 pub availability: Archived<N, D, G, P>,
215}
216
217pub struct PathCertificates<'path, 'document, N, D, G, P> {
221 path: &'path CheckedPath<'document>,
222 archive: Location<N, D, G>,
223 entries: OwnedVec<ArchivedCertificate<N, D, G, P>>,
224 all_covered: bool,
225}
226
227impl<'path, 'document, N: Copy, D: Copy, G: Copy, P>
228 PathCertificates<'path, 'document, N, D, G, P>
229{
230 #[must_use]
232 pub fn path(&self) -> &'path CheckedPath<'document> {
233 self.path
234 }
235 #[must_use]
237 pub fn archive(&self) -> Location<N, D, G> {
238 self.archive
239 }
240 #[must_use]
242 pub fn entries(&self) -> &[ArchivedCertificate<N, D, G, P>] {
243 &self.entries
244 }
245 #[must_use]
248 pub fn all_certificates_covered(&self) -> bool {
249 self.all_covered
250 }
251}
252
253#[derive(Debug, Clone, Copy, PartialEq, Eq)]
255pub enum ArchiveError<N> {
256 Index(IndexError<N>),
258 Coverage(CoverageError<N>),
260 NotArchive {
262 property: N,
264 },
265}
266
267impl<'source, N: Copy + Eq, D: Copy + Eq, G: Copy + Eq, P: Copy, O, W: Work, I>
268 Index<'source, N, D, G, P, O, W, I>
269{
270 pub fn new<Q: Query<Id = N, Document = D, Generation = G, Work = W>>(
276 _issuer: I,
277 signature: N,
278 open: &'source [O],
279 query: &Q,
280 ) -> Result<Self, IndexError<N>> {
281 query.admit(signature, 1).map_err(IndexError::Scope)?;
282 let execution = query.execution();
283 Ok(Self {
284 snapshot: query.snapshot(),
285 signature,
286 keys: execution.map(),
287 entries: execution.vector(),
288 open,
289 issuer: PhantomData,
290 })
291 }
292
293 pub fn insert<Q: Query<Id = N, Document = D, Generation = G, Work = W>>(
301 &mut self,
302 _issuer: I,
303 artifact: ArtifactRef<'_, 'source>,
304 occurrence: Occurrence<N, D, G, P>,
305 query: &Q,
306 ) -> Result<(), IndexError<N>> {
307 if occurrence.location.snapshot != self.snapshot || query.snapshot() != self.snapshot {
310 return Err(IndexError::Foreign {
311 signature: self.signature,
312 });
313 }
314 self.insert_key(artifact.identity(), occurrence, query)?;
315 if let ArtifactRef::Ocsp(response) = artifact {
316 for certificate in 0..response.certificates().len() {
317 self.admit(query)?;
318 self.insert_key(
319 ArtifactKey {
320 kind: Kind::Certificate,
321 bytes: response.certificates()[certificate].as_bytes(),
322 },
323 Occurrence {
324 embedded_certificate: Some(certificate),
325 ..occurrence
326 },
327 query,
328 )?;
329 }
330 }
331 Ok(())
332 }
333
334 #[must_use]
336 pub fn open(&self) -> &'source [O] {
337 self.open
338 }
339
340 #[must_use]
342 pub fn signature(&self) -> N {
343 self.signature
344 }
345
346 #[must_use]
348 pub fn snapshot(&self) -> Snapshot<D, G> {
349 self.snapshot
350 }
351
352 pub fn certificate<'view, 'query, Q: Query<Id = N, Document = D, Generation = G>>(
355 &'view self,
356 value: &Certificate<'_>,
357 query: &'query Q,
358 ) -> Lookup<'view, 'query, 'source, N, D, G, P, O, W, Q, I> {
359 self.find(Kind::Certificate, value.as_bytes(), query)
360 }
361 pub fn crl<'view, 'query, Q: Query<Id = N, Document = D, Generation = G>>(
364 &'view self,
365 value: &CertificateList<'_>,
366 query: &'query Q,
367 ) -> Lookup<'view, 'query, 'source, N, D, G, P, O, W, Q, I> {
368 self.find(Kind::Crl, value.as_bytes(), query)
369 }
370 pub fn ocsp<'view, 'query, Q: Query<Id = N, Document = D, Generation = G>>(
373 &'view self,
374 value: &BasicResponse<'_>,
375 query: &'query Q,
376 ) -> Lookup<'view, 'query, 'source, N, D, G, P, O, W, Q, I> {
377 self.find(Kind::Basic, value.as_bytes(), query)
378 }
379
380 pub fn artifact<'view, 'query, Q: Query<Id = N, Document = D, Generation = G>>(
382 &'view self,
383 artifact: ArtifactRef<'_, '_>,
384 query: &'query Q,
385 ) -> Lookup<'view, 'query, 'source, N, D, G, P, O, W, Q, I> {
386 let key = artifact.identity();
387 self.find(key.kind, key.bytes, query)
388 }
389
390 pub fn require_signature<Q: Query<Id = N, Document = D, Generation = G>>(
392 &self,
393 signature: N,
394 query: &Q,
395 ) -> Result<(), IndexError<N>> {
396 self.admit(query)?;
397 let same =
398 query
399 .equal(self.signature, signature)
400 .map_err(|cause| IndexError::Resource {
401 signature: self.signature,
402 cause,
403 })?;
404 if !same {
405 return Err(IndexError::Foreign { signature });
406 }
407 Ok(())
408 }
409
410 pub fn archived<Q: Query<Id = N, Document = D, Generation = G>, C: Work>(
422 &self,
423 artifact: ArtifactRef<'_, '_>,
424 coverage: &Coverage<N, D, G, C, I>,
425 evidence: &Verified<N, D, G, I>,
426 query: &Q,
427 ) -> Result<Archived<N, D, G, P>, ArchiveError<N>>
428 where
429 N: HashWork,
430 {
431 if evidence.purpose() != Purpose::Archive {
432 return Err(ArchiveError::NotArchive {
433 property: evidence.property(),
434 });
435 }
436 if evidence.token().snapshot != self.snapshot {
438 return Err(ArchiveError::Index(IndexError::Foreign {
439 signature: self.signature,
440 }));
441 }
442 self.require_signature(evidence.signature(), query)
443 .map_err(ArchiveError::Index)?;
444 coverage
445 .require_evidence(evidence, evidence.property(), query)
446 .map_err(ArchiveError::Coverage)?;
447 let key = artifact.identity();
448 let copies = self
449 .find(key.kind, key.bytes, query)
450 .map_err(ArchiveError::Index)?;
451 let mut found = false;
452 for copy in copies {
453 let copy = copy.map_err(ArchiveError::Index)?;
454 found = true;
455 if coverage
458 .selects(copy.location.node, query)
459 .map_err(ArchiveError::Coverage)?
460 {
461 return Ok(Archived::Present(copy));
462 }
463 }
464 Ok(if found {
465 Archived::Uncovered
466 } else {
467 Archived::Missing
468 })
469 }
470
471 pub fn archived_path<'path, 'document, Q, C: Work>(
482 &self,
483 path: &'path CheckedPath<'document>,
484 coverage: &Coverage<N, D, G, C, I>,
485 evidence: &Verified<N, D, G, I>,
486 query: &Q,
487 ) -> Result<PathCertificates<'path, 'document, N, D, G, P>, ArchiveError<N>>
488 where
489 N: HashWork,
490 Q: Query<Id = N, Document = D, Generation = G>,
491 {
492 query
493 .admit(self.signature, 1)
494 .map_err(|cause| ArchiveError::Index(IndexError::Scope(cause)))?;
495 let mut entries = query.execution().vector();
496 let mut all_covered = true;
497 let mut record = |certificate, role| {
498 let availability = self.archived(
499 ArtifactRef::Certificate(certificate),
500 coverage,
501 evidence,
502 query,
503 )?;
504 if !matches!(availability, Archived::Present(_)) {
505 all_covered = false;
506 }
507 entries
508 .try_push(ArchivedCertificate { role, availability })
509 .map_err(|cause| {
510 ArchiveError::Index(IndexError::Resource {
511 signature: self.signature,
512 cause,
513 })
514 })
515 };
516 if let Some(certificate) = path.anchor().certificate() {
517 record(certificate, PathCertificate::Anchor)?;
518 }
519 for (ordinal, member) in path.members().iter().enumerate() {
520 self.admit(query).map_err(ArchiveError::Index)?;
521 record(member.certificate(), PathCertificate::Member(ordinal))?;
522 }
523 Ok(PathCertificates {
524 path,
525 archive: evidence.token(),
526 entries: entries.into_owned(),
527 all_covered,
528 })
529 }
530
531 pub fn admit<Q: Query<Id = N, Document = D, Generation = G>>(
533 &self,
534 query: &Q,
535 ) -> Result<(), IndexError<N>> {
536 if self.snapshot != query.snapshot() {
537 return Err(IndexError::Foreign {
538 signature: self.signature,
539 });
540 }
541 query.admit(self.signature, 2).map_err(IndexError::Scope)
542 }
543
544 fn insert_key<Q: Query<Id = N, Document = D, Generation = G, Work = W>>(
545 &mut self,
546 key: ArtifactKey<'source>,
547 value: Occurrence<N, D, G, P>,
548 query: &Q,
549 ) -> Result<(), IndexError<N>> {
550 query.admit(self.signature, 1).map_err(IndexError::Scope)?;
551 let resource = |cause| IndexError::Resource {
552 signature: self.signature,
553 cause,
554 };
555 let previous = self
556 .keys
557 .get(&key, query.execution())
558 .map(Option::<&(usize, usize)>::copied)
559 .map_err(resource)?;
560 let next = self.entries.len();
561 self.entries
562 .try_push(Entry { value, next: None })
563 .map_err(resource)?;
564 let head = previous.map_or(next, |(head, _)| head);
565 self.keys.try_insert(key, (head, next)).map_err(resource)?;
566 if let Some((_, tail)) = previous {
567 self.entries[tail].next = Some(next);
568 }
569 Ok(())
570 }
571
572 fn find<'view, 'query, Q: Query<Id = N, Document = D, Generation = G>>(
573 &'view self,
574 kind: Kind,
575 bytes: &[u8],
576 query: &'query Q,
577 ) -> Lookup<'view, 'query, 'source, N, D, G, P, O, W, Q, I> {
578 self.admit(query)?;
579 query.admit(self.signature, 1).map_err(IndexError::Scope)?;
580 let next = self
581 .keys
582 .get(&ArtifactKey { kind, bytes }, query.execution())
583 .map(|value| value.map(|&(head, _)| head))
584 .map_err(|cause| IndexError::Resource {
585 signature: self.signature,
586 cause,
587 })?;
588 Ok(Occurrences {
589 index: self,
590 query,
591 next,
592 })
593 }
594}
595
596pub type Lookup<'view, 'query, 'source, N, D, G, P, O, W, Q, I> =
598 Result<Occurrences<'view, 'query, 'source, N, D, G, P, O, W, Q, I>, IndexError<N>>;
599
600pub struct Occurrences<'view, 'query, 'source, N, D, G, P, O, W: Work, Q, I> {
604 index: &'view Index<'source, N, D, G, P, O, W, I>,
605 query: &'query Q,
606 next: Option<usize>,
607}
608
609impl<N: Copy + Eq, D: Copy + Eq, G: Copy + Eq, P: Copy, O, W: Work, Q, I> Iterator
610 for Occurrences<'_, '_, '_, N, D, G, P, O, W, Q, I>
611where
612 Q: Query<Id = N, Document = D, Generation = G>,
613{
614 type Item = Result<Occurrence<N, D, G, P>, IndexError<N>>;
615 fn next(&mut self) -> Option<Self::Item> {
616 let next = self.next.take()?;
617 if let Err(error) = self.index.admit(self.query) {
618 return Some(Err(error));
619 }
620 let entry = &self.index.entries[next];
621 self.next = entry.next;
622 Some(Ok(entry.value))
623 }
624}
625
626impl<N: Copy + Eq, D: Copy + Eq, G: Copy + Eq, P: Copy, O, W: Work, Q, I> core::iter::FusedIterator
627 for Occurrences<'_, '_, '_, N, D, G, P, O, W, Q, I>
628where
629 Q: Query<Id = N, Document = D, Generation = G>,
630{
631}