Skip to main content
KeyOS API Reference

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, AppSeed, BluetoothChallengeSecret, DeviceId, FirmwareTimestamp, GetDeviceIdError,
9    LockoutOptions, LoginFailed, MasterKeyState, OsVersionInfo, PinEntryMode, PinError, ScChallengeError,
10    ScProof, 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<AppSeed, 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// Don't derive Debug: the prefix is the first four characters of the PIN.
91#[derive(server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
92#[response(Result<[SecurityWord; 2], AccessDenied>)]
93pub struct GetSecurityWords {
94    pub pin_prefix: Vec<u8>,
95}
96
97#[cfg(not(keyos))]
98#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
99#[response(())]
100pub struct SetAttempts(pub u32);
101
102#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
103#[response(Result<[u8; 32], AccessDenied>)]
104pub struct GetSeedFingerprint;
105
106#[derive(Clone, server::Message, ZeroizeOnDrop, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
107#[response(Result<[u8; 32], AccessDenied>)]
108pub struct ComputeSeedFingerprint(pub Seed);
109
110#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
111#[response(Result<[u8; 64], AccessDenied>)]
112pub struct SignWithFidoKey(pub [u8; 32]);
113
114#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
115#[response(Result<[u8; 64], AccessDenied>)]
116pub struct GetFidoPubkey;
117
118#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
119#[response(Result<Option<OsVersionInfo>, AccessDenied>)]
120pub struct GetOsVersionInfo;
121
122/// A message to get the bootloader build date as a Unix timestamp.
123/// Used by Recovery OS for bootloader rollback prevention during Core Recovery.
124/// Added separately from `GetOsVersionInfo` for backward compatibility.
125#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
126#[response(Result<Option<u64>, AccessDenied>)]
127pub struct GetBootloaderBuildDate;
128
129/// A message sent from the server to the device. Includes the intermediate challenge, deadline and the server
130/// signature, in the following binary format:
131/// ```text
132/// ------------------------------------
133/// | challenge | deadline | signature |
134/// | 32 bytes  | 8 bytes  | 64 bytes  |
135/// ------------------------------------
136/// ```
137#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
138#[response(Result<ScProof, ScChallengeError>)]
139pub struct ScChallenge(pub [u8; Self::SIZE]);
140
141impl ScChallenge {
142    pub const SIZE: usize = 104;
143}
144
145#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
146#[response(Result<bool, AccessDenied>)]
147pub struct IsPinSet;
148
149#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
150#[response(Result<DeviceId, GetDeviceIdError>)]
151pub struct GetDeviceId;
152
153#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
154#[response(Result<[u8; 32], AccessDenied>)]
155pub struct KeycardAuthenticityMac(pub [u8; 32]);
156
157#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
158#[response(BluetoothChallengeSecret)]
159pub struct GetBluetoothChallengeSecret;
160
161#[derive(Debug, server::Message)]
162#[response(())]
163pub struct SetBluetoothCheckSecretSent;
164
165#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
166#[response(())]
167pub struct SetBluetoothDeviceId(pub [u8; 8]);
168
169#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
170#[response(Result<[u8; 32], AccessDenied>)]
171pub struct GetRandom;
172
173#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
174#[response(PinEntryMode)]
175pub struct GetPinEntryMode;
176
177#[derive(Debug, server::Message)]
178#[response(MasterKeyState)]
179pub struct GetMasterKeyState;
180
181#[derive(Debug, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
182#[event(DiskEncryptionKeysReady)]
183pub struct SubscribeDiskEncryptionKeysReady;
184
185#[derive(Debug, Clone, Copy)]
186pub struct DiskEncryptionKeysReady;
187
188impl AsScalar<1> for DiskEncryptionKeysReady {
189    fn as_scalar(&self) -> [u32; 1] { [0] }
190}
191
192impl FromScalar<1> for DiskEncryptionKeysReady {
193    fn from_scalar(_: [u32; 1]) -> Self { Self }
194}
195
196impl FromScalar<1> for MasterKeyState {
197    fn from_scalar([value]: [u32; 1]) -> Self {
198        match value {
199            0 => MasterKeyState::Erased,
200            1 => MasterKeyState::Onboarding,
201            2 => MasterKeyState::Normal,
202            _ => MasterKeyState::Unknown,
203        }
204    }
205}
206
207impl AsScalar<1> for MasterKeyState {
208    fn as_scalar(&self) -> [u32; 1] {
209        [match self {
210            MasterKeyState::Erased => 0,
211            MasterKeyState::Onboarding => 1,
212            MasterKeyState::Normal => 2,
213            MasterKeyState::Unknown => 3,
214        }]
215    }
216}