1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
//! The module's error state, where every crate can see it.
//!
//! A cryptographic module that finds itself wrong -- a known-answer test that
//! fails, corruption detected by its host -- must stop producing output, and
//! must not start again until it is restarted. `ic_fips` runs the tests and
//! holds the rest of the module's state, but the primitive crates cannot
//! depend on it: it depends on them. So the one fact they all need lives
//! here, below them, as a flag that can be set and never cleared.
//!
//! Once [`enter_error_state`] has been called, every operation in this
//! library that can report an error reports
//! [`ErrorKind::ModuleErrorState`] and does nothing else: encryption and decryption, signing and verification,
//! key generation and agreement, MACs, hashes and XOFs, key derivation and
//! random generation. The operations that return `bool` return `false`.
//!
//! Hashes, XOFs and MACs refuse on output -- `finalize`, `digest`, `xof`, a
//! reader's `read` or `fill`, `mac` -- so an object made before the failure
//! produces nothing after it. Making one and feeding it input produce no
//! output, and are not refused. Until 0.3.0 those interfaces had no error to
//! return and could not refuse at all; they were the gate's stated limit.
//!
//! # What this does not gate
//!
//! The primitives call one another through `ic_core::traits::internal`, which
//! does not refuse: a signature or a KDF refuses at its own entry, and does
//! not check again for each hash on the way to its answer. That module is
//! hidden and not API; a caller who names it has stepped inside the boundary.
//!
//! One thing that could refuse is left ungated on purpose: a block cipher
//! object's `encrypt_block`, `decrypt_block` and `encrypt_blocks`. They are
//! the inner loop of every mode, and every mode refuses at its own entry, as
//! does `BlockCipher::new`; a check per block would be paid by all of them
//! to stop only raw single-block use of a key made before the failure.
//!
//! Parsing and encoding, which use no key, are not gated either.
//!
//! # Before the self-tests
//!
//! In the default build nothing here requires the self-tests to have run: a
//! primitive called before `ic_fips::initialize` works, and only a module that
//! has failed refuses. `ic_fips::check` is the gate for that.
//!
//! A build with `--cfg ic_approved_only` closes it. There, every operation
//! that consults [`operational`] also refuses, with
//! [`ErrorKind::ModuleErrorState`], until `ic_fips::initialize` has run the
//! known-answer tests and they have passed. FIPS 140-3 asks for the
//! self-tests before a service is first used, and in that build it no longer
//! depends on the caller asking for them.
//!
//! While the tests run, the primitives they call are let through, since the
//! tests are made of them. A second thread that calls a primitive in that
//! window is let through too: nothing below `ic_fips` can tell the two threads
//! apart without `std`. A program that starts threads before `initialize`
//! returns should not use the library from them until it does.
//!
//! This repository's own test suites are made of primitive calls that do not
//! go through `ic_fips`, and the crates that hold them cannot depend on it, so
//! `scripts/approved-only.sh` runs them with `--cfg ic_startup_gate_off` as
//! well, which turns this gate, and only this gate, off. It is a test switch:
//! a build with it does not run its self-tests before use. The same script
//! then runs the tests that show the gate refusing, without it.
//!
//! # Cost
//!
//! One relaxed load of one byte per operation.
use crate::;
use ;
static FAILED: AtomicBool = new;
const UNTESTED: u8 = 0;
const TESTING: u8 = 1;
const PASSED: u8 = 2;
/// How far the known-answer tests have got. Consulted only in a build with
/// `--cfg ic_approved_only`; see the module documentation.
static SELF_TESTS: AtomicU8 = new;
/// Whether this build refuses service until the self-tests have passed.
const STARTUP_GATE: bool = cfg!;
/// Record that the known-answer tests have started.
///
/// For `ic_fips::initialize`, which runs them. Until [`self_tests_passed`] is
/// called the primitives the tests use are let through, so that the tests can
/// run at all.
/// Record that every known-answer test passed.
///
/// For `ic_fips::initialize`. Calling it any other way skips the tests it
/// stands for; the error state still overrides it.
/// Whether the known-answer tests have passed in this process.
/// Put the module into its error state.
///
/// There is no way back short of restarting the process, by design: nothing
/// in this library clears the flag. Applications call
/// `ic_fips::enter_error_state`, which calls this.
/// Pass on the result of a conditional self-test, entering the error state
/// if it failed.
///
/// A conditional self-test is one a module runs on its own work as it goes:
/// the pairwise consistency test on a key pair it has just generated. Its
/// input is the module's own output, never a caller's, so a failure is not
/// something a peer can cause -- it means this module computed two things
/// that should agree and do not, and nothing it computes afterwards can be
/// vouched for.
///
/// Key generation wraps its test in this. The test functions themselves do
/// not enter the state, so that they can be shown rejecting a mismatched
/// pair without ending the process that shows it.
/// Whether the module is in its error state.
/// `Ok(())` unless the module is in its error state -- or, in a build with
/// `--cfg ic_approved_only`, has not yet passed its self-tests.
///
/// The first line of every operation that can refuse:
///
/// ```
/// fn service() -> ic_core::Result<()> {
/// ic_core::module::operational()?;
/// // ...
/// Ok(())
/// }
/// # ic_core::module::self_tests_passed(); // what ic_fips::initialize records
/// # service().unwrap();
/// ```