xml_sec/xmldsig/verify/session/
key_receipt.rs1use super::*;
4pub use crate::provider::KeyAssociation;
5
6pub struct SelectedKeyReceipt<'a> {
10 seal: &'a [u8; 1],
11 signature: NodeIdentity,
12 provider: &'a dyn crate::provider::CryptoProvider,
13 public: Option<&'a [u8]>,
14 binding: Option<&'a crate::provider::ProviderBinding>,
15}
16
17impl SelectedKeyReceipt<'_> {
18 pub fn signature(&self) -> NodeIdentity {
20 self.signature
21 }
22
23 pub fn provider_name(&self) -> &'static str {
25 self.provider.name()
26 }
27
28 pub fn has_public_evidence(&self) -> bool {
31 self.public.is_some()
32 }
33}
34
35impl<W: Work> VerifiedSession<'_, '_, '_, W> {
36 pub fn with_key_association_in<Q: Work, R, E>(
45 &self,
46 signature: NodeIdentity,
47 expected: structured_pkix::path::WorkingKey<'_>,
48 work: &Q,
49 visitor: impl FnOnce(KeyAssociation) -> Result<R, E>,
50 ) -> Result<R, CatalogueError<E>> {
51 let index = self
52 .authenticated_signature_in(signature, work)
53 .map_err(CatalogueError::Processing)?;
54 flatten_catalogue(self.with_key_receipt_at_in(index, work, |receipt| {
55 let outcome = self
56 .associate_receipt_in(index, &receipt, expected, work)
57 .map_err(CatalogueError::Processing)?;
58 visitor(outcome).map_err(CatalogueError::Visitor)
59 }))
60 }
61
62 fn with_key_receipt_at_in<Q: Work, R, E>(
63 &self,
64 index: usize,
65 work: &Q,
66 visitor: impl for<'a> FnOnce(SelectedKeyReceipt<'a>) -> Result<R, E>,
67 ) -> Result<R, CatalogueError<E>> {
68 self.signature_method_in(index, work)
69 .map_err(CatalogueError::Processing)?;
70 work.charge_work(1)
71 .map_err(|error| CatalogueError::Processing(error.into()))?;
72 let capture = &self.operations[index].capture;
73 let key = capture.key.borrow();
74 visitor(SelectedKeyReceipt {
75 seal: &capture.seal,
76 signature: self.evidence.signatures()[index].identity,
77 provider: self.context.provider,
78 public: key.public.as_deref(),
79 binding: key.binding.as_ref(),
80 })
81 .map_err(CatalogueError::Visitor)
82 }
83
84 fn associate_receipt_in<Q: Work>(
85 &self,
86 index: usize,
87 receipt: &SelectedKeyReceipt<'_>,
88 expected: structured_pkix::path::WorkingKey<'_>,
89 work: &Q,
90 ) -> Result<KeyAssociation, DsigError> {
91 work.charge_work(1)?;
92 let capture = &self.operations[index].capture;
93 if !std::ptr::eq(receipt.seal, &capture.seal)
94 || receipt.signature != self.evidence.signatures()[index].identity
95 || !std::ptr::eq(receipt.provider, self.context.provider)
96 {
97 return Err(DsigError::InvalidRequest {
98 reason: "key receipt belongs to another selected operation",
99 });
100 }
101 let domain_matches = match (receipt.binding, receipt.provider.binding()) {
102 (None, None) => true,
103 (Some(key), Some(provider)) => key.matches(provider),
104 _ => false,
105 };
106 if receipt.public.is_some() && !domain_matches {
107 return Err(crate::provider::ProviderError::External(
108 crate::provider::ExternalProviderError::Binding,
109 )
110 .into());
111 }
112 let outcome = match receipt.public {
113 Some(public) => {
114 receipt
115 .provider
116 .associate_verification_key(public, expected, &|cost| work.charge_work(cost))?
117 }
118 None => KeyAssociation::Unproven,
119 };
120 work.charge_work(1)?;
121 Ok(outcome)
122 }
123}
124
125impl<W: Work, Q: Work> SelectedSignature<'_, '_, '_, '_, W, Q> {
126 pub fn with_key_receipt<R, E>(
129 &self,
130 visitor: impl for<'a> FnOnce(SelectedKeyReceipt<'a>) -> Result<R, E>,
131 ) -> Result<R, CatalogueError<E>> {
132 self.session
133 .with_key_receipt_at_in(self.index, self.work, visitor)
134 }
135
136 pub fn associate_key<R, E>(
142 &self,
143 receipt: &SelectedKeyReceipt<'_>,
144 expected: structured_pkix::path::WorkingKey<'_>,
145 visitor: impl FnOnce(KeyAssociation) -> Result<R, E>,
146 ) -> Result<R, CatalogueError<E>> {
147 self.signature_method()
148 .map_err(CatalogueError::Processing)?;
149 let outcome = self
150 .session
151 .associate_receipt_in(self.index, receipt, expected, self.work)
152 .map_err(CatalogueError::Processing)?;
153 visitor(outcome).map_err(CatalogueError::Visitor)
154 }
155}