Coverage Report

Created: 2025-07-23 07:04

/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
}