security/
messages.rs

1// SPDX-FileCopyrightText: 2023 Foundation Devices, Inc. <hello@foundation.xyz>
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4use server::{AsScalar, FromScalar};
5use zeroize::ZeroizeOnDrop;
6
7use crate::{
8    AccessDenied, BluetoothChallengeSecret, DeviceId, FirmwareTimestamp, GetDeviceIdError, LockoutOptions,
9    LoginFailed, MasterKeyState, OsVersionInfo, PinEntryMode, PinError, ScChallengeError, ScProof,
10    SecurityWord, Seed,
11};
12
13#[derive(Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
14#[response(Result<(), PinError>)]
15pub struct SetSeedAndPin {
16    pub seed: Seed,
17    pub pin: RawPin,
18    pub pin_entry: PinEntryMode,
19}
20
21#[derive(Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
22#[response(Result<(), PinError>)]
23pub struct ChangePin {
24    pub pin: RawPin,
25    pub seed: Option<Seed>,
26    pub pin_entry: PinEntryMode,
27}
28
29#[derive(Clone, ZeroizeOnDrop, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
30pub struct RawPin(pub String);
31
32#[derive(Clone, ZeroizeOnDrop, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
33#[response(Result<(), LoginFailed>)]
34pub struct Login {
35    pub pin: RawPin,
36}
37
38#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
39#[response(Result<u32, AccessDenied>)]
40pub struct GetAttemptsRemaining;
41
42#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
43#[response(Result<u32, AccessDenied>)]
44pub struct GetFactoryResetCounter;
45
46#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
47#[response(Result<Option<Seed>, AccessDenied>)]
48pub struct GetSeed;
49
50#[derive(Clone, ZeroizeOnDrop, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
51#[response(Result<(), AccessDenied>)]
52pub struct SetSeed(pub Seed);
53
54#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
55#[response(Result<[u8; 32], AccessDenied>)]
56pub struct GetAppSeed;
57
58#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
59#[response(Result<FirmwareTimestamp, AccessDenied>)]
60pub struct GetFirmwareTimestamp;
61
62#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
63#[response(Result<(), AccessDenied>)]
64pub struct SetFirmwareTimestamp(pub FirmwareTimestamp);
65
66#[derive(Debug, server::Message)]
67#[response(())]
68pub struct Logout;
69
70#[derive(Debug, server::Message)]
71#[response(bool)]
72pub struct LoggedIn;
73
74#[cfg(not(keyos))]
75#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
76#[response(String)]
77pub struct GetPin;
78
79#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
80#[response(Result<(), AccessDenied>)]
81pub struct Lockout {
82    pub lockout_options: LockoutOptions,
83    pub reboot: bool,
84}
85
86#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
87#[response(Result<[u8; 64], AccessDenied>)]
88pub struct SignWithSecurityCheckKey(pub [u8; 32]);
89
90#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
91#[response(Result<[SecurityWord; 2], AccessDenied>)]
92pub struct GetSecurityWords {
93    pub pin_prefix: Vec<u8>,
94}
95
96#[cfg(not(keyos))]
97#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
98#[response(())]
99pub struct SetAttempts(pub u32);
100
101#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
102#[response(Result<[u8; 32], AccessDenied>)]
103pub struct GetSeedFingerprint;
104
105#[derive(Clone, server::Message, ZeroizeOnDrop, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
106#[response(Result<[u8; 32], AccessDenied>)]
107pub struct ComputeSeedFingerprint(pub Seed);
108
109#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
110#[response(Result<[u8; 64], AccessDenied>)]
111pub struct SignWithFidoKey(pub [u8; 32]);
112
113#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
114#[response(Result<[u8; 64], AccessDenied>)]
115pub struct GetFidoPubkey;
116
117#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
118#[response(Result<Option<OsVersionInfo>, AccessDenied>)]
119pub struct GetOsVersionInfo;
120
121/// A message to get the bootloader build date as a Unix timestamp.
122/// Used by Recovery OS for bootloader rollback prevention during Core Recovery.
123/// Added separately from `GetOsVersionInfo` for backward compatibility.
124#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
125#[response(Result<Option<u64>, AccessDenied>)]
126pub struct GetBootloaderBuildDate;
127
128/// A message sent from the server to the device. Includes the intermediate challenge, deadline and the server
129/// signature, in the following binary format:
130/// ```text
131/// ------------------------------------
132/// | challenge | deadline | signature |
133/// | 32 bytes  | 8 bytes  | 64 bytes  |
134/// ------------------------------------
135/// ```
136#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
137#[response(Result<ScProof, ScChallengeError>)]
138pub struct ScChallenge(pub [u8; Self::SIZE]);
139
140impl ScChallenge {
141    pub const SIZE: usize = 104;
142}
143
144#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
145#[response(Result<bool, AccessDenied>)]
146pub struct IsPinSet;
147
148#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
149#[response(Result<DeviceId, GetDeviceIdError>)]
150pub struct GetDeviceId;
151
152#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
153#[response(Result<[u8; 32], AccessDenied>)]
154pub struct KeycardAuthenticityMac(pub [u8; 32]);
155
156#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
157#[response(BluetoothChallengeSecret)]
158pub struct GetBluetoothChallengeSecret;
159
160#[derive(Debug, server::Message)]
161#[response(())]
162pub struct SetBluetoothCheckSecretSent;
163
164#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
165#[response(())]
166pub struct SetBluetoothDeviceId(pub [u8; 8]);
167
168#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
169#[response(Result<[u8; 32], AccessDenied>)]
170pub struct GetRandom;
171
172#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
173#[response(PinEntryMode)]
174pub struct GetPinEntryMode;
175
176#[derive(Debug, server::Message)]
177#[response(MasterKeyState)]
178pub struct GetMasterKeyState;
179
180#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
181#[event(DiskEncryptionKeysReady)]
182pub struct SubscribeDiskEncryptionKeysReady;
183
184#[derive(Debug, Clone, Copy)]
185pub struct DiskEncryptionKeysReady;
186
187impl AsScalar<1> for DiskEncryptionKeysReady {
188    fn as_scalar(&self) -> [u32; 1] { [0] }
189}
190
191impl FromScalar<1> for DiskEncryptionKeysReady {
192    fn from_scalar(_: [u32; 1]) -> Self { Self }
193}
194
195impl FromScalar<1> for MasterKeyState {
196    fn from_scalar([value]: [u32; 1]) -> Self {
197        match value {
198            0 => MasterKeyState::Erased,
199            1 => MasterKeyState::Onboarding,
200            2 => MasterKeyState::Normal,
201            _ => MasterKeyState::Unknown,
202        }
203    }
204}
205
206impl AsScalar<1> for MasterKeyState {
207    fn as_scalar(&self) -> [u32; 1] {
208        [match self {
209            MasterKeyState::Erased => 0,
210            MasterKeyState::Onboarding => 1,
211            MasterKeyState::Normal => 2,
212            MasterKeyState::Unknown => 3,
213        }]
214    }
215}