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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
// Copyright (C) 2026 Qualia2FA contributors
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License as published by the Free
// Software Foundation; either version 3 of the License, or (at your option) any
// later version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, see <https://www.gnu.org/licenses/>.
//! Hardware key store backends, one module per platform.
//!
//! **Only the module of the current target platform provides an implementation**; every
//! other platform falls back to `platform_stub`.
//!
//! # Status per platform
//!
//! | Platform | Backend | Status |
//! |---|---|---|
//! | Windows | CNG `NCrypt*` + TPM 2.0 | **implemented and verified on real hardware** |
//! | Windows (no TPM) | CNG software KSP | implemented (reports `Backend::Software`) |
//! | Android | Keystore, StrongBox preferred | **implemented and verified on real hardware** |
//! | macOS | Secure Enclave | **placeholder** |
//! | Linux | TPM 2.0 | **placeholder** |
//! | iOS | Secure Enclave | **placeholder** |
//! | Other (BSD, …) | undecided | **placeholder** |
//!
//! "Placeholder" means **every operation fails**; it is not a usable software
//! implementation. The exact failure behaviour is documented in the `platform_stub`
//! module.
//!
//! # Single entry point: [`crate::keystore::platform::PlatformKeyStore`]
//!
//! Upper layers must **not** reference a concrete backend such as
//! `windows::WindowsKeyStore` directly. Use
//! [`crate::keystore::platform::PlatformKeyStore`] instead: it exists on every platform,
//! so the FFI and UI layers compile with **zero** platform branches. Platform differences
//! are confined to the `cfg` attributes in this file rather than spread over every call
//! site.
//!
//! # Adding a platform backend
//!
//! 1. Add `<platform>.rs` in this directory, implementing [`crate::DeviceKeyStore`] and
//! [`crate::DeviceSigner`].
//! 2. Point the matching `pub use platform_stub::StubKeyStore as PlatformKeyStore;` line
//! in this file at the new module, and update `platform_backend_is_implemented`
//! accordingly.
//! 3. Make sure the platform can provide **P-256 ECDSA**; this is a hard requirement, see
//! the crate documentation.
//! 4. **Never** fall back to a software key because hardware is unavailable: return
//! `UnsupportedPlatform` or `HardwareUnavailable` so that the caller can ask the user.
//! 5. Implement **both** master key forms as well — [`crate::DirectMasterKeyStore`] and
//! [`crate::WrappedMasterKeyStore`] — and point the two matching
//! `PlatformDirectMasterKeyStore` / `PlatformWrappedMasterKeyStore` lines here at them.
//! A platform that can do only one of the two returns
//! [`crate::Error::UnsupportedPlatform`] from the other, rather than pretending.
//!
//! Requirements common to every backend:
//!
//! - Private keys **must not** leave the hardware, nor enter this process's address
//! space.
//! - The signing interface takes a **digest** and returns the raw **`r||s`** (64 bytes),
//! matching the convention of [`crate::keystore::traits::DIGEST_LEN`].
//! - A key-encryption key of the wrapped form **must not** be exportable, and no operation
//! that would reveal it may appear in an interface.
//! - Failures are returned as [`crate::KeyStoreError`]; **no panics**.
//! - Every `unsafe` block carries a `// SAFETY:` justification.
/// The Android platform API, as the platform declares it.
///
/// Test-only: it holds the declarations every JNI descriptor of the Android backend is
/// checked against, and no runtime code. Every target compiles it, so the check runs
/// wherever `cargo test` does rather than only on Android.
/// Android Keystore backend, reached over JNI.
/// Placeholder implementation shared by all platforms without a backend.
///
/// Compiled on every platform except Windows and Android. "Not implemented yet" is the same
/// situation on all of them, hence a single implementation; what each platform *plans* to
/// use is recorded in [`platform_identity`].
///
/// It also supplies `PlatformProvider` on Android, which has no provider to choose between:
/// there the security level of a key is decided when the key is generated, not by opening a
/// provider.
/// The key store implementation available on the current platform.
///
/// This is the **entry point upper layers should use**. It exists on every platform, so
/// callers need no platform branches.
pub use WindowsKeyStore as PlatformKeyStore;
/// The key store implementation available on the current platform.
pub use AndroidKeyStore as PlatformKeyStore;
/// The key store implementation available on the current platform (this platform's
/// backend is not implemented yet).
pub use StubKeyStore as PlatformKeyStore;
/// The **direct** master key store of the current platform.
///
/// One of the two ways of holding the application's master key: the platform store keeps the
/// material itself. See [`crate::keystore::DirectMasterKeyStore`] for the contract.
pub use WindowsDirectMasterKeyStore as PlatformDirectMasterKeyStore;
/// The direct master key store of the current platform.
pub use AndroidDirectMasterKeyStore as PlatformDirectMasterKeyStore;
/// The direct master key store of the current platform (this platform's backend is not
/// implemented yet).
pub use StubDirectMasterKeyStore as PlatformDirectMasterKeyStore;
/// The **wrapped** master key store of the current platform.
///
/// The other way of holding the application's master key: a non-exportable
/// key-encryption key in the platform store wraps it, and only the wrapped bytes are
/// persisted. See [`crate::keystore::WrappedMasterKeyStore`] for the contract.
pub use WindowsWrappedMasterKeyStore as PlatformWrappedMasterKeyStore;
/// The wrapped master key store of the current platform.
pub use AndroidWrappedMasterKeyStore as PlatformWrappedMasterKeyStore;
/// The wrapped master key store of the current platform (this platform's backend is not
/// implemented yet).
pub use StubWrappedMasterKeyStore as PlatformWrappedMasterKeyStore;
/// The storage provider of the current platform.
pub use WindowsProvider as PlatformProvider;
/// The storage provider of the current platform (this platform's backend is not
/// implemented yet).
pub use StubProvider as PlatformProvider;
/// Main types of the Windows backend.
///
/// Re-exported here so that callers only have to remember **one** path
/// (`qualia_dik::keystore::platform::WindowsKeyStore`) instead of which submodule it
/// lives in.
///
/// New code should prefer [`crate::keystore::platform::PlatformKeyStore`]: it is
/// portable, whereas this alias only exists on Windows.
pub use ;
/// Master key stores of the Windows backend.
///
/// Both forms live here: the direct one keeps the material in the provider, the wrapped one
/// keeps a non-exportable key-encryption key there. New code should prefer
/// [`crate::keystore::platform::PlatformDirectMasterKeyStore`] and
/// [`crate::keystore::platform::PlatformWrappedMasterKeyStore`].
pub use ;
/// What this platform is called, and which backend it plans to use.
///
/// Both values appear only in **error messages and diagnostics**, so they are compile-time
/// constants rather than runtime probes. They live here rather than in `platform_stub.rs`
/// so that each platform's name and plan can be looked up in one place.