libcryptsetup_rs/luks2/
token.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5use std::ptr;
6
7use crate::{consts::flags::CryptActivate, device::CryptDevice, err::LibcryptErr};
8
9use libc::{c_char, c_int, c_uint, c_void};
10
11/// Type representing the token status. This type wraps the `CRYPT_TOKEN_*` values and the optional corresponding token type as a string.
12pub enum CryptTokenInfo {
13    /// Token invalid
14    Invalid,
15    /// Token is free (empty)
16    Inactive,
17    /// Active internal token with driver
18    Internal(String),
19    /// Active internal token (reserved name) with missing token driver
20    InternalUnknown(String),
21    /// Active external (user defined) token with driver
22    External(String),
23    /// Active external (user defined) token with missing token driver
24    ExternalUnknown(String),
25}
26
27impl CryptTokenInfo {
28    /// Convert a token status code into `CryptTokenInfo`
29    pub fn from_status(code: c_uint, type_: Option<String>) -> Result<Self, LibcryptErr> {
30        Ok(match code {
31            libcryptsetup_rs_sys::crypt_token_info_CRYPT_TOKEN_INVALID => CryptTokenInfo::Invalid,
32            libcryptsetup_rs_sys::crypt_token_info_CRYPT_TOKEN_INACTIVE => CryptTokenInfo::Inactive,
33            libcryptsetup_rs_sys::crypt_token_info_CRYPT_TOKEN_INTERNAL => {
34                CryptTokenInfo::Internal(type_.ok_or(LibcryptErr::InvalidConversion)?)
35            }
36            libcryptsetup_rs_sys::crypt_token_info_CRYPT_TOKEN_INTERNAL_UNKNOWN => {
37                CryptTokenInfo::InternalUnknown(type_.ok_or(LibcryptErr::InvalidConversion)?)
38            }
39            libcryptsetup_rs_sys::crypt_token_info_CRYPT_TOKEN_EXTERNAL => {
40                CryptTokenInfo::External(type_.ok_or(LibcryptErr::InvalidConversion)?)
41            }
42            libcryptsetup_rs_sys::crypt_token_info_CRYPT_TOKEN_EXTERNAL_UNKNOWN => {
43                CryptTokenInfo::ExternalUnknown(type_.ok_or(LibcryptErr::InvalidConversion)?)
44            }
45            _ => return Err(LibcryptErr::InvalidConversion),
46        })
47    }
48}
49
50#[allow(clippy::from_over_into)]
51impl Into<u32> for CryptTokenInfo {
52    fn into(self) -> u32 {
53        match self {
54            CryptTokenInfo::Invalid => libcryptsetup_rs_sys::crypt_token_info_CRYPT_TOKEN_INVALID,
55            CryptTokenInfo::Inactive => libcryptsetup_rs_sys::crypt_token_info_CRYPT_TOKEN_INACTIVE,
56            CryptTokenInfo::Internal(_) => {
57                libcryptsetup_rs_sys::crypt_token_info_CRYPT_TOKEN_INTERNAL
58            }
59            CryptTokenInfo::InternalUnknown(_) => {
60                libcryptsetup_rs_sys::crypt_token_info_CRYPT_TOKEN_INTERNAL_UNKNOWN
61            }
62            CryptTokenInfo::External(_) => {
63                libcryptsetup_rs_sys::crypt_token_info_CRYPT_TOKEN_EXTERNAL
64            }
65            CryptTokenInfo::ExternalUnknown(_) => {
66                libcryptsetup_rs_sys::crypt_token_info_CRYPT_TOKEN_EXTERNAL_UNKNOWN
67            }
68        }
69    }
70}
71
72/// Token input for `CryptLuks2Token::json_set`
73pub enum TokenInput<'a> {
74    /// Add a new token to any free slot
75    AddToken(&'a serde_json::Value),
76    /// Replace the specified token
77    ReplaceToken(c_uint, &'a serde_json::Value),
78    /// Remove the specified token
79    RemoveToken(c_uint),
80}
81
82/// Handle for LUKS2 token operations
83pub struct CryptLuks2TokenHandle<'a> {
84    reference: &'a mut CryptDevice,
85}
86
87impl<'a> CryptLuks2TokenHandle<'a> {
88    pub(crate) fn new(reference: &'a mut CryptDevice) -> Self {
89        CryptLuks2TokenHandle { reference }
90    }
91
92    /// Get contents of a token in JSON format
93    pub fn json_get(&mut self, token: c_uint) -> Result<serde_json::Value, LibcryptErr> {
94        let mut ptr: *const c_char = std::ptr::null();
95        errno_int_success!(mutex!(libcryptsetup_rs_sys::crypt_token_json_get(
96            self.reference.as_ptr(),
97            token as c_int,
98            &mut ptr as *mut _,
99        )))
100        .and_then(|_| from_str_ptr!(ptr))
101        .and_then(|s| serde_json::from_str(s).map_err(LibcryptErr::JsonError))
102    }
103
104    /// Set contents of a token in JSON format
105    pub fn json_set(&mut self, input: TokenInput<'_>) -> Result<c_uint, LibcryptErr> {
106        let (token, json) = match input {
107            TokenInput::AddToken(json) => (libcryptsetup_rs_sys::CRYPT_ANY_TOKEN, Some(json)),
108            TokenInput::ReplaceToken(token, json) => (token as i32, Some(json)),
109            TokenInput::RemoveToken(token) => (token as i32, None),
110        };
111        let json_cstring = match json {
112            Some(j) => Some(
113                serde_json::to_string(j)
114                    .map_err(LibcryptErr::JsonError)
115                    .and_then(|s| to_cstring!(s))?,
116            ),
117            None => None,
118        };
119        errno_int_success!(mutex!(libcryptsetup_rs_sys::crypt_token_json_set(
120            self.reference.as_ptr(),
121            token,
122            json_cstring
123                .as_ref()
124                .map(|cs| cs.as_ptr())
125                .unwrap_or(ptr::null()),
126        )))
127        .map(|rc| rc as c_uint)
128    }
129
130    /// Get the token info for a specific token
131    pub fn status(&mut self, token: c_uint) -> Result<CryptTokenInfo, LibcryptErr> {
132        let mut ptr: *const c_char = std::ptr::null();
133        let code = mutex!(libcryptsetup_rs_sys::crypt_token_status(
134            self.reference.as_ptr(),
135            token as c_int,
136            &mut ptr as *mut _,
137        ));
138        CryptTokenInfo::from_status(
139            code,
140            match ptr_to_option!(ptr) {
141                Some(p) => Some(from_str_ptr_to_owned!(p)?),
142                None => None,
143            },
144        )
145    }
146
147    /// Create new LUKS2 keyring token
148    pub fn luks2_keyring_set(
149        &mut self,
150        token: Option<c_uint>,
151        key_description: &str,
152    ) -> Result<c_uint, LibcryptErr> {
153        let description_cstring = to_cstring!(key_description)?;
154        errno_int_success!(mutex!(libcryptsetup_rs_sys::crypt_token_luks2_keyring_set(
155            self.reference.as_ptr(),
156            token
157                .map(|t| t as c_int)
158                .unwrap_or(libcryptsetup_rs_sys::CRYPT_ANY_TOKEN),
159            &libcryptsetup_rs_sys::crypt_token_params_luks2_keyring {
160                key_description: description_cstring.as_ptr(),
161            } as *const _,
162        )))
163        .map(|rc| rc as c_uint)
164    }
165
166    /// Get LUKS2 keyring token description
167    pub fn luks2_keyring_get(&mut self, token: c_uint) -> Result<String, LibcryptErr> {
168        let mut params = libcryptsetup_rs_sys::crypt_token_params_luks2_keyring {
169            key_description: std::ptr::null(),
170        };
171        errno_int_success!(mutex!(libcryptsetup_rs_sys::crypt_token_luks2_keyring_get(
172            self.reference.as_ptr(),
173            token as c_int,
174            &mut params as *mut _,
175        )))
176        .and_then(|_| from_str_ptr!(params.key_description).map(|s| s.to_string()))
177    }
178
179    /// Assign token to keyslot
180    ///
181    /// `None` for keyslot assigns all keyslots to the token
182    pub fn assign_keyslot(
183        &mut self,
184        token: c_uint,
185        keyslot: Option<c_uint>,
186    ) -> Result<(), LibcryptErr> {
187        errno_int_success!(mutex!(libcryptsetup_rs_sys::crypt_token_assign_keyslot(
188            self.reference.as_ptr(),
189            token as c_int,
190            keyslot
191                .map(|k| k as c_int)
192                .unwrap_or(libcryptsetup_rs_sys::CRYPT_ANY_SLOT),
193        )))
194        .map(|_| ())
195    }
196
197    /// Unassign token from keyslot
198    ///
199    /// `None` for keyslot unassigns the token from all active keyslots
200    pub fn unassign_keyslot(
201        &mut self,
202        token: c_uint,
203        keyslot: Option<c_uint>,
204    ) -> Result<(), LibcryptErr> {
205        errno_int_success!(mutex!(libcryptsetup_rs_sys::crypt_token_unassign_keyslot(
206            self.reference.as_ptr(),
207            token as c_int,
208            keyslot
209                .map(|k| k as c_int)
210                .unwrap_or(libcryptsetup_rs_sys::CRYPT_ANY_SLOT),
211        )))
212        .map(|_| ())
213    }
214
215    /// Check if token is assigned
216    #[allow(clippy::wrong_self_convention)]
217    pub fn is_assigned(&mut self, token: c_uint, keyslot: c_uint) -> Result<bool, LibcryptErr> {
218        let rc = mutex!(libcryptsetup_rs_sys::crypt_token_is_assigned(
219            self.reference.as_ptr(),
220            token as c_int,
221            keyslot as c_int,
222        ));
223        if rc == 0 {
224            Ok(true)
225        } else if rc == libc::ENOENT {
226            Ok(false)
227        } else {
228            Err(LibcryptErr::IOError(std::io::Error::from_raw_os_error(-rc)))
229        }
230    }
231
232    /// Activate device or check key using a token
233    pub fn activate_by_token<T>(
234        &mut self,
235        name: Option<&str>,
236        token: Option<c_uint>,
237        usrdata: Option<&mut T>,
238        flags: CryptActivate,
239    ) -> Result<c_uint, LibcryptErr> {
240        let name_cstring_option = match name {
241            Some(n) => Some(to_cstring!(n)?),
242            None => None,
243        };
244        let usrdata_ptr = match usrdata {
245            Some(reference) => (reference as *mut T).cast::<c_void>(),
246            None => ptr::null_mut(),
247        };
248        errno_int_success!(mutex!(libcryptsetup_rs_sys::crypt_activate_by_token(
249            self.reference.as_ptr(),
250            match name_cstring_option {
251                Some(ref s) => s.as_ptr(),
252                None => std::ptr::null(),
253            },
254            token
255                .map(|t| t as c_int)
256                .unwrap_or(libcryptsetup_rs_sys::CRYPT_ANY_TOKEN),
257            usrdata_ptr,
258            flags.bits(),
259        )))
260        .map(|rc| rc as c_uint)
261    }
262}
263
264/// Register token handler
265pub fn register(
266    name: &'static str,
267    open: libcryptsetup_rs_sys::crypt_token_open_func,
268    buffer_free: libcryptsetup_rs_sys::crypt_token_buffer_free_func,
269    validate: libcryptsetup_rs_sys::crypt_token_validate_func,
270    dump: libcryptsetup_rs_sys::crypt_token_dump_func,
271) -> Result<(), LibcryptErr> {
272    if name.get(name.len() - 1..) != Some("\0") {
273        return Err(LibcryptErr::NoNull(name));
274    }
275    let handler = libcryptsetup_rs_sys::crypt_token_handler {
276        name: name.as_ptr().cast::<c_char>(),
277        open,
278        buffer_free,
279        validate,
280        dump,
281    };
282    errno!(mutex!(libcryptsetup_rs_sys::crypt_token_register(
283        &handler as *const libcryptsetup_rs_sys::crypt_token_handler,
284    )))
285}