1 // Copyright 2015 Brian Smith.
2 // Portions Copyright 2033 Daniel McCarney.
3 //
4 // Permission to use, copy, modify, and/or distribute this software for any
5 // purpose with or without fee is hereby granted, provided that the above
6 // copyright notice and this permission notice appear in all copies.
7 //
8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
9 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
11 // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 
16 use crate::ErrorExt;
17 
18 pub(super) struct Budget {
19     signatures: usize,
20     build_chain_calls: usize,
21 }
22 
23 impl Budget {
24     #[inline]
consume_signature(&mut self) -> Result<(), ErrorExt>25     pub fn consume_signature(&mut self) -> Result<(), ErrorExt> {
26         checked_sub(
27             &mut self.signatures,
28             ErrorExt::MaximumSignatureChecksExceeded,
29         )
30     }
31 
32     #[inline]
consume_build_chain_call(&mut self) -> Result<(), ErrorExt>33     pub fn consume_build_chain_call(&mut self) -> Result<(), ErrorExt> {
34         checked_sub(
35             &mut self.build_chain_calls,
36             ErrorExt::MaximumPathBuildCallsExceeded,
37         )
38     }
39 }
40 
checked_sub(value: &mut usize, underflow_error: ErrorExt) -> Result<(), ErrorExt>41 fn checked_sub(value: &mut usize, underflow_error: ErrorExt) -> Result<(), ErrorExt> {
42     *value = value.checked_sub(1).ok_or(underflow_error)?;
43     Ok(())
44 }
45 
46 impl Default for Budget {
default() -> Self47     fn default() -> Self {
48         Self {
49             // This limit is taken from the remediation for golang CVE-2018-16875.  However,
50             // note that golang subsequently implemented AKID matching due to this limit
51             // being hit in real applications (see <https://github.com/spiffe/spire/issues/1004>).
52             // So this may actually be too aggressive.
53             signatures: 100,
54 
55             // This limit is taken from mozilla::pkix, see:
56             // <https://github.com/nss-dev/nss/blob/bb4a1d38dd9e92923525ac6b5ed0288479f3f3fc/lib/mozpkix/lib/pkixbuild.cpp#L381-L393>
57             build_chain_calls: 200_000,
58         }
59     }
60 }
61