Skip to content

Commit 00d299f

Browse files
committed
[WIP] Implement smartcard section form save/load_device.
1 parent 2d2783c commit 00d299f

File tree

14 files changed

+134
-24
lines changed

14 files changed

+134
-24
lines changed

Cargo.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ libparsec_platform_device_loader = { path = "libparsec/crates/platform_device_lo
9999
libparsec_platform_http_proxy = { path = "libparsec/crates/platform_http_proxy", default-features = false }
100100
libparsec_platform_ipc = { path = "libparsec/crates/platform_ipc", default-features = false }
101101
libparsec_platform_mountpoint = { path = "libparsec/crates/platform_mountpoint", default-features = false }
102+
libparsec_platform_pki = { path = "libparsec/crates/platform_pki", default-features = false }
102103
libparsec_platform_realm_export = { path = "libparsec/crates/platform_realm_export", default-features = false }
103104
libparsec_platform_storage = { path = "libparsec/crates/platform_storage", default-features = false }
104105
libparsec_protocol = { path = "libparsec/crates/protocol", default-features = false }

cli/src/commands/device/change_authentication.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,13 @@ pub async fn main(args: Args) -> anyhow::Result<()> {
5353
}
5454
}
5555

56-
AvailableDeviceType::Smartcard => DeviceAccessStrategy::Smartcard {
57-
key_file: device.key_file_path.clone(),
58-
},
56+
AvailableDeviceType::Smartcard => {
57+
todo!("read smartcard");
58+
DeviceAccessStrategy::Smartcard {
59+
certificate_reference: todo!(),
60+
key_file: device.key_file_path.clone(),
61+
}
62+
}
5963

6064
AvailableDeviceType::Keyring => DeviceAccessStrategy::Keyring {
6165
key_file: device.key_file_path.clone(),

cli/src/commands/device/overwrite_server_url.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ pub async fn main(args: Args) -> anyhow::Result<()> {
3434

3535
AvailableDeviceType::Smartcard => DeviceAccessStrategy::Smartcard {
3636
key_file: device.key_file_path.clone(),
37+
certificate_reference: todo!("read smartcard"),
3738
},
3839

3940
AvailableDeviceType::Keyring => DeviceAccessStrategy::Keyring {

cli/src/utils.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ pub async fn load_and_unlock_device(
248248
}
249249
AvailableDeviceType::Smartcard => DeviceAccessStrategy::Smartcard {
250250
key_file: device.key_file_path.clone(),
251+
certificate_reference: todo!("read smartcard"),
251252
},
252253
AvailableDeviceType::Keyring => DeviceAccessStrategy::Keyring {
253254
key_file: device.key_file_path.clone(),

libparsec/crates/platform_device_loader/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ vendored-dbus = ["keyring/vendored"]
1818
[dependencies]
1919
libparsec_crypto = { workspace = true }
2020
libparsec_platform_async = { workspace = true }
21+
libparsec_platform_pki = { workspace = true }
2122
libparsec_testbed = { workspace = true, optional = true }
2223
libparsec_types = { workspace = true }
2324

libparsec/crates/platform_device_loader/src/native/mod.rs

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ use libparsec_platform_async::future::FutureExt as _;
66
use std::path::{Path, PathBuf};
77
use uuid::Uuid;
88

9-
use libparsec_types::prelude::*;
10-
119
use crate::{
12-
get_device_archive_path, ArchiveDeviceError, ListAvailableDeviceError, LoadCiphertextKeyError,
13-
LoadDeviceError, ReadFileError, RemoveDeviceError, SaveDeviceError, UpdateDeviceError,
14-
DEVICE_FILE_EXT,
10+
encrypt_device, get_device_archive_path, ArchiveDeviceError, ListAvailableDeviceError,
11+
LoadCiphertextKeyError, LoadDeviceError, ReadFileError, RemoveDeviceError, SaveDeviceError,
12+
UpdateDeviceError, DEVICE_FILE_EXT,
1513
};
14+
use libparsec_platform_pki::{decrypt_secret_key, encrypt_secret_key};
15+
use libparsec_types::prelude::*;
1616

1717
const KEYRING_SERVICE: &str = "parsec";
1818

@@ -152,9 +152,16 @@ pub(super) async fn load_ciphertext_key(
152152
Ok(key)
153153
}
154154

155-
(DeviceAccessStrategy::Smartcard { .. }, DeviceFile::Smartcard(_)) => {
156-
todo!("Load smartcard device")
157-
}
155+
(
156+
DeviceAccessStrategy::Smartcard {
157+
certificate_reference,
158+
..
159+
},
160+
DeviceFile::Smartcard(device),
161+
) => Ok(
162+
decrypt_secret_key(&device.encrypted_key, certificate_reference)
163+
.map_err(|_| LoadCiphertextKeyError::InvalidData)?,
164+
),
158165

159166
(
160167
DeviceAccessStrategy::AccountVault { ciphertext_key, .. },
@@ -303,8 +310,48 @@ pub(super) async fn save_device(
303310
save_content(key_file, &file_content).await?;
304311
}
305312

306-
DeviceAccessStrategy::Smartcard { .. } => {
307-
todo!("Save smartcard device")
313+
DeviceAccessStrategy::Smartcard {
314+
key_file,
315+
certificate_reference,
316+
} => {
317+
// Generate a random key
318+
let secret_key = SecretKey::generate();
319+
320+
// Encrypt the key using the public key related to a certificate from the store
321+
322+
let (encrypted_key, certificate_id, certificate_sha1) =
323+
encrypt_secret_key(&secret_key, certificate_reference)
324+
.map_err(|e| SaveDeviceError::Internal(e.into()))?;
325+
326+
// May check if we are able to decrypt the encrypted key from the previous step
327+
assert_eq!(
328+
decrypt_secret_key(&encrypted_key, certificate_reference)
329+
.map_err(|e| SaveDeviceError::Internal(e.into()))?,
330+
secret_key
331+
);
332+
333+
// Use the generated key to encrypt the device content
334+
let ciphertext = encrypt_device(device, &secret_key);
335+
336+
// Save
337+
let file_content = DeviceFile::Smartcard(DeviceFileSmartcard {
338+
created_on,
339+
protected_on,
340+
server_url: server_url.clone(),
341+
organization_id: device.organization_id().to_owned(),
342+
user_id: device.user_id,
343+
device_id: device.device_id,
344+
human_handle: device.human_handle.to_owned(),
345+
device_label: device.device_label.to_owned(),
346+
certificate_id,
347+
certificate_sha1: Some(Bytes::copy_from_slice(certificate_sha1.as_ref())),
348+
encrypted_key,
349+
ciphertext,
350+
});
351+
352+
let file_content = file_content.dump();
353+
354+
save_content(key_file, &file_content).await?;
308355
}
309356

310357
DeviceAccessStrategy::AccountVault {

libparsec/crates/platform_device_loader/src/testbed.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -342,9 +342,12 @@ pub(crate) fn maybe_load_device(
342342
}
343343
}
344344
(
345-
DeviceAccessStrategy::Smartcard { key_file: kf },
346-
DeviceAccessStrategy::Smartcard { key_file: c_kf },
347-
) if c_kf == kf => Some(Ok(c_device.to_owned())),
345+
DeviceAccessStrategy::Smartcard { key_file: kf, .. },
346+
DeviceAccessStrategy::Smartcard { key_file: c_kf, .. },
347+
) if c_kf == kf => {
348+
todo!("compare certificate reference");
349+
//Some(Ok(c_device.to_owned()))
350+
}
348351
(
349352
DeviceAccessStrategy::Keyring { key_file: kf },
350353
DeviceAccessStrategy::Keyring { key_file: c_kf },

libparsec/crates/platform_device_loader/tests/units/list.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ async fn list_devices(tmp_path: TmpPath) {
165165
.parse()
166166
.unwrap(),
167167
device_label: "PC1".parse().unwrap(),
168-
certificate_id: "Mallory's certificate".to_string(),
168+
certificate_id: "Mallory's certificate".into(),
169169
certificate_sha1: Some(
170170
hex!("4682e01bc3e22fdfff1c33b551dfad8e49295005")
171171
.as_ref()

libparsec/crates/platform_pki/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ workspace = true
1515
thiserror = { workspace = true }
1616
bytes = { workspace = true }
1717

18+
libparsec_crypto = { workspace = true }
19+
20+
1821
[target.'cfg(target_os = "windows")'.dependencies]
1922
schannel = { workspace = true }
2023
windows-sys = { workspace = true, features = ["Win32_Security_Cryptography_UI"] }

0 commit comments

Comments
 (0)