structured_xades/validation/
ref_key.rs1use super::{ReferenceIdentifier, ReferenceProperty, ResponderIdentifier};
4use crate::{
5 binary::{self, BinaryXml, Location},
6 xml::Access,
7};
8use structured_asn1::{Reader, Tag};
9use structured_pkix::{
10 Certificate,
11 algorithm::digest::AsnDigest,
12 ocsp::{ResponderId, ResponderMatch},
13};
14
15#[derive(Debug)]
17pub enum ResponderKeyError<E> {
18 Index {
20 index: usize,
22 },
23 Encoding(structured_asn1::Error),
25 Responder(structured_pkix::Error),
27 Trailing {
29 offset: u64,
31 },
32 Callback(E),
34}
35
36pub type ReferenceKeyResult<X, E> = binary::BinaryResult<
38 Option<binary::LocatedValue<ResponderMatch, X>>,
39 X,
40 ResponderKeyError<structured_pkix::error::CallbackError<E>>,
41>;
42
43pub fn with_responder_key<X: BinaryXml, R, E>(
52 xml: &X,
53 references: &ReferenceProperty<X::Id, X::Document, X::Generation>,
54 index: usize,
55 operation: &Reader<'_>,
56 visitor: impl for<'source> FnOnce(&'source [u8]) -> Result<R, E>,
57) -> binary::BinaryResult<Option<binary::LocatedValue<R, X>>, X, ResponderKeyError<E>> {
58 with_key_at(xml, references, index, operation, |hash, _, _| {
59 visitor(hash)
60 })
61}
62
63pub fn matches_reference_key<'k, X: BinaryXml, D, DE>(
69 xml: &X,
70 references: &ReferenceProperty<X::Id, X::Document, X::Generation>,
71 index: usize,
72 certificate: &Certificate<'_>,
73 digest: &'k D,
74 operation: &Reader<'_>,
75) -> ReferenceKeyResult<X, DE>
76where
77 D: AsnDigest<'k, Error = DE>,
78{
79 with_key_at(xml, references, index, operation, |hash, reader, at| {
80 ResponderId::KeyHash(hash).matches_certificate(
81 certificate,
82 digest,
83 &reader.execution(),
84 "xades.ocspIdentifier.byKey",
85 at,
86 )
87 })
88}
89
90fn with_key_at<X: BinaryXml, R, E>(
91 xml: &X,
92 references: &ReferenceProperty<X::Id, X::Document, X::Generation>,
93 index: usize,
94 operation: &Reader<'_>,
95 visitor: impl for<'source> FnOnce(&'source [u8], &Reader<'source>, u64) -> Result<R, E>,
96) -> binary::BinaryResult<Option<binary::LocatedValue<R, X>>, X, ResponderKeyError<E>> {
97 let location = Location {
98 snapshot: references.snapshot(),
99 node: references.node(),
100 };
101 let work = operation.execution();
102 Access::new(xml, references.snapshot(), &work)
103 .query(references.node(), |_, _, _| Ok(()))
104 .map_err(|cause| binary::Error::Access { location, cause })?;
105 let Some(entry) = references.entries().get(index) else {
106 return Err(binary::Error::Callback {
107 location,
108 cause: ResponderKeyError::Index { index },
109 });
110 };
111 let ReferenceIdentifier::Ocsp {
112 responder: ResponderIdentifier::Key(node),
113 ..
114 } = entry.identifier()
115 else {
116 return Ok(None);
117 };
118 let location = Location {
119 snapshot: references.snapshot(),
120 node,
121 };
122 binary::with_der_reader(xml, location, operation, |reader| {
123 let element = reader
124 .expect(Tag::context(true, 2))
125 .map_err(ResponderKeyError::Encoding)?;
126 let responder =
127 ResponderId::read_element(reader, &element).map_err(ResponderKeyError::Responder)?;
128 if !reader.is_empty() {
129 return Err(ResponderKeyError::Trailing {
130 offset: reader.offset(),
131 });
132 }
133 let ResponderId::KeyHash(hash) = responder else {
134 unreachable!("checked byKey tag produced a name");
135 };
136 visitor(hash, reader, element.span().start)
137 .map(|value| Some(binary::Located { location, value }))
138 .map_err(ResponderKeyError::Callback)
139 })
140}