/rust/registry/src/index.crates.io-6f17d22bba15001f/aws-lc-rs-1.13.0/src/fips.rs
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. |
2 | | // SPDX-License-Identifier: Apache-2.0 OR ISC |
3 | | |
4 | | /// Retrieve the FIPS module service status. |
5 | | #[allow(dead_code)] // appease clippy |
6 | | #[cfg(all(feature = "fips", debug_assertions))] |
7 | | pub(crate) fn get_fips_service_status() -> FipsServiceStatus<()> { |
8 | | if let Some(status) = indicator::get_status() { |
9 | | if status { |
10 | | FipsServiceStatus::Approved(()) |
11 | | } else { |
12 | | FipsServiceStatus::NonApproved(()) |
13 | | } |
14 | | } else { |
15 | | FipsServiceStatus::Unset(()) |
16 | | } |
17 | | } |
18 | | |
19 | | #[inline] |
20 | 0 | pub(crate) fn set_fips_service_status_unapproved() { |
21 | 0 | #[cfg(all(feature = "fips", debug_assertions))] |
22 | 0 | indicator::set_unapproved(); |
23 | 0 | } |
24 | | |
25 | | #[allow(dead_code)] |
26 | | #[cfg(all(feature = "fips", debug_assertions))] |
27 | | #[inline] |
28 | | pub(crate) fn clear_fips_service_status() { |
29 | | indicator::clear(); |
30 | | } |
31 | | |
32 | | #[cfg(all(feature = "fips", debug_assertions))] |
33 | | pub(crate) mod indicator { |
34 | | use core::cell::Cell; |
35 | | |
36 | | thread_local! { |
37 | | static STATUS_INDICATOR: Cell<Option<bool>> = const { Cell::new(None) }; |
38 | | } |
39 | | |
40 | | // Retrieves and returns the current indicator status while resetting the indicator |
41 | | // for future calls. |
42 | | pub fn get_status() -> Option<bool> { |
43 | | STATUS_INDICATOR.with(|v| { |
44 | | let swap = Cell::new(None); |
45 | | v.swap(&swap); |
46 | | swap.take() |
47 | | }) |
48 | | } |
49 | | |
50 | | pub fn set_approved() { |
51 | | STATUS_INDICATOR.with(|v| v.set(Some(true))); |
52 | | } |
53 | | |
54 | | pub fn set_unapproved() { |
55 | | STATUS_INDICATOR.with(|v| v.set(Some(false))); |
56 | | } |
57 | | |
58 | | pub fn clear() { |
59 | | STATUS_INDICATOR.with(|v| v.set(None)); |
60 | | } |
61 | | } |
62 | | |
63 | | #[cfg(all(feature = "fips", debug_assertions))] |
64 | | #[inline] |
65 | | pub(crate) fn service_indicator_before_call() -> u64 { |
66 | | unsafe { aws_lc::FIPS_service_indicator_before_call() } |
67 | | } |
68 | | |
69 | | #[cfg(all(feature = "fips", debug_assertions))] |
70 | | #[inline] |
71 | | pub(crate) fn service_indicator_after_call() -> u64 { |
72 | | unsafe { aws_lc::FIPS_service_indicator_after_call() } |
73 | | } |
74 | | |
75 | | /// The FIPS Module Service Status |
76 | | #[allow(dead_code)] // appease clippy |
77 | | #[cfg(all(feature = "fips", debug_assertions))] |
78 | | #[allow(clippy::module_name_repetitions)] |
79 | | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
80 | | pub(crate) enum FipsServiceStatus<R> { |
81 | | /// Indicates that the current thread is using approved FIPS cryptographic services. |
82 | | Approved(R), |
83 | | |
84 | | /// Indicates that the current thread has used non-approved FIPS cryptographic services. |
85 | | /// The service indicator status can be reset using `reset_fips_service_status`. |
86 | | /// `reset_fips_service_status` will return `NonApprovedMode` if the service used a non-approved |
87 | | /// service, and automatically resets the service status for you. |
88 | | NonApproved(R), |
89 | | |
90 | | /// Indicates that the service indicator is not set |
91 | | Unset(R), |
92 | | } |
93 | | |
94 | | #[cfg(all(feature = "fips", debug_assertions))] |
95 | | impl<R> FipsServiceStatus<R> { |
96 | | /// Maps a `ServiceStatus<R>` to a `ServiceStatus<S>` by applying a function to a contained value. |
97 | | #[allow(dead_code)] |
98 | | pub fn map<S, F>(self, op: F) -> FipsServiceStatus<S> |
99 | | where |
100 | | F: FnOnce(R) -> S, |
101 | | { |
102 | | match self { |
103 | | FipsServiceStatus::Approved(v) => FipsServiceStatus::Approved(op(v)), |
104 | | FipsServiceStatus::NonApproved(v) => FipsServiceStatus::NonApproved(op(v)), |
105 | | FipsServiceStatus::Unset(v) => FipsServiceStatus::Unset(op(v)), |
106 | | } |
107 | | } |
108 | | } |
109 | | |
110 | | macro_rules! indicator_check { |
111 | | ($function:expr) => {{ |
112 | | #[cfg(all(feature = "fips", debug_assertions))] |
113 | | { |
114 | | use crate::fips::{service_indicator_after_call, service_indicator_before_call}; |
115 | | let before = service_indicator_before_call(); |
116 | | let result = $function; |
117 | | let after = service_indicator_after_call(); |
118 | | if before == after { |
119 | | crate::fips::indicator::set_unapproved(); |
120 | | result |
121 | | } else { |
122 | | crate::fips::indicator::set_approved(); |
123 | | result |
124 | | } |
125 | | } |
126 | | #[cfg(any(not(feature = "fips"), not(debug_assertions)))] |
127 | | { |
128 | | $function |
129 | | } |
130 | | }}; |
131 | | } |
132 | | |
133 | | pub(crate) use indicator_check; |
134 | | |
135 | | #[allow(unused_macros)] |
136 | | #[cfg(all(feature = "fips", debug_assertions))] |
137 | | macro_rules! check_fips_service_status { |
138 | | ($function:expr) => {{ |
139 | | // Clear the current indicator status first by retrieving it |
140 | | use $crate::fips::{clear_fips_service_status, get_fips_service_status}; |
141 | | clear_fips_service_status(); |
142 | | // do the expression |
143 | | let result = $function; |
144 | | // Check indicator after expression |
145 | | get_fips_service_status().map(|()| result) |
146 | | }}; |
147 | | } |
148 | | |
149 | | #[allow(unused_imports)] |
150 | | #[cfg(all(feature = "fips", debug_assertions))] |
151 | | pub(crate) use check_fips_service_status; |
152 | | |
153 | | #[allow(unused_macros)] |
154 | | #[cfg(all(feature = "fips", debug_assertions))] |
155 | | macro_rules! assert_fips_status_indicator { |
156 | | ($function:expr, $expect:path) => { |
157 | | assert_fips_status_indicator!($function, $expect, "unexpected service indicator") |
158 | | }; |
159 | | ($function:expr, $expect:path, $message:literal) => {{ |
160 | | match crate::fips::check_fips_service_status!($function) { |
161 | | $expect(v) => v, |
162 | | _ => panic!($message), |
163 | | } |
164 | | }}; |
165 | | } |
166 | | |
167 | | #[allow(unused_imports)] |
168 | | #[cfg(all(feature = "fips", debug_assertions))] |
169 | | pub(crate) use assert_fips_status_indicator; |
170 | | |
171 | | #[cfg(test)] |
172 | | mod tests { |
173 | | |
174 | | #[cfg(all(feature = "fips", debug_assertions))] |
175 | | #[test] |
176 | | fn test_service_status() { |
177 | | use crate::fips::FipsServiceStatus; |
178 | | |
179 | | assert_eq!( |
180 | | FipsServiceStatus::Approved(true), |
181 | | FipsServiceStatus::Approved(()).map(|()| true) |
182 | | ); |
183 | | assert_eq!( |
184 | | FipsServiceStatus::NonApproved(true), |
185 | | FipsServiceStatus::NonApproved(()).map(|()| true) |
186 | | ); |
187 | | assert_eq!( |
188 | | FipsServiceStatus::Unset(true), |
189 | | FipsServiceStatus::Unset(()).map(|()| true) |
190 | | ); |
191 | | } |
192 | | } |