From e16757bc9c7e021d608472348426d16d7c16c33f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Fri, 16 Feb 2024 17:49:49 +0100 Subject: [PATCH] Implement optimization migrations --- Cargo.lock | 18 ++++---- Cargo.toml | 16 +++---- components/apps/Cargo.toml | 3 +- components/apps/src/dispatch.rs | 43 ++++++++++++++++++ components/apps/src/lib.rs | 80 ++++++++++++++++++++++----------- 5 files changed, 118 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3c096f78..4d4392e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,7 +5,7 @@ version = 3 [[package]] name = "admin-app" version = "0.1.0" -source = "git+https://github.com/Nitrokey/admin-app.git?tag=v0.1.0-nitrokey.10#c6c87cfad4d94c4910c87e870bae759330f6f634" +source = "git+https://github.com/Nitrokey/admin-app.git?rev=c584a1911ab65670729ea068fe54e0bae7f2459e#c584a1911ab65670729ea068fe54e0bae7f2459e" dependencies = [ "apdu-dispatch", "cbor-smol", @@ -486,7 +486,7 @@ dependencies = [ [[package]] name = "cbor-smol" version = "0.4.0" -source = "git+https://github.com/Nitrokey/cbor-smol.git?tag=v0.4.0-nitrokey.1#cdedd94cc62214f99f0e4bb35f9e7a67f50a45c1" +source = "git+https://github.com/Nitrokey/cbor-smol.git?rev=bac1ac69dd0117d1f80f3f5e1d3b60ba8987ad70#bac1ac69dd0117d1f80f3f5e1d3b60ba8987ad70" dependencies = [ "delog", "heapless", @@ -1175,7 +1175,7 @@ dependencies = [ [[package]] name = "fido-authenticator" version = "0.1.1" -source = "git+https://github.com/Nitrokey/fido-authenticator.git?tag=v0.1.1-nitrokey.12#3db1f6fdba65ede3a05e7f0e4489145e22cde3af" +source = "git+https://github.com/Nitrokey/fido-authenticator.git?rev=a3757fb1b5d8c9d0485ca7f3524caed7b629dc04#a3757fb1b5d8c9d0485ca7f3524caed7b629dc04" dependencies = [ "apdu-dispatch", "ctap-types", @@ -1183,6 +1183,7 @@ dependencies = [ "delog", "heapless", "iso7816", + "littlefs2", "serde", "serde-indexed", "serde_cbor", @@ -1746,7 +1747,7 @@ checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "littlefs2" version = "0.4.0" -source = "git+https://github.com/trussed-dev/littlefs2?rev=ebd27e49ca321089d01d8c9b169c4aeb58ceeeca#ebd27e49ca321089d01d8c9b169c4aeb58ceeeca" +source = "git+https://github.com/nitrokey/littlefs2.git?rev=99b1a9832c46c9097e73ca1fa43e119026e2068f#99b1a9832c46c9097e73ca1fa43e119026e2068f" dependencies = [ "bitflags 1.3.2", "cstr_core", @@ -3201,7 +3202,7 @@ dependencies = [ [[package]] name = "trussed" version = "0.1.0" -source = "git+https://github.com/Nitrokey/trussed.git?tag=v0.1.0-nitrokey.18#cb7bd328549293077cd9d6c2e9e42df62180db96" +source = "git+https://github.com/Nitrokey/trussed.git?rev=371e8f7a07817c2ed57978bd86e3412bd9877647#371e8f7a07817c2ed57978bd86e3412bd9877647" dependencies = [ "aes", "bitflags 2.4.2", @@ -3238,11 +3239,12 @@ dependencies = [ [[package]] name = "trussed-auth" version = "0.2.2" -source = "git+https://github.com/trussed-dev/trussed-auth?rev=4b8191f248c26cb074cdac887c7f3f48f9c449a4#4b8191f248c26cb074cdac887c7f3f48f9c449a4" +source = "git+https://github.com/Nitrokey/trussed-auth?rev=7ad0ab1f592dabb3646840cbb11769a988166fb4#7ad0ab1f592dabb3646840cbb11769a988166fb4" dependencies = [ "chacha20poly1305", "hkdf", "hmac", + "littlefs2", "rand_core", "serde", "serde-byte-array", @@ -3283,7 +3285,7 @@ dependencies = [ [[package]] name = "trussed-se050-backend" version = "0.2.0" -source = "git+https://github.com/Nitrokey/trussed-se050-backend.git?tag=v0.2.0#f48a4f2bb2d3f5f9fba5d361401f91cd9c2ee8f1" +source = "git+https://github.com/Nitrokey/trussed-se050-backend.git?rev=393bff2ead093f3a043c3e04ed7a706649f66b7f#393bff2ead093f3a043c3e04ed7a706649f66b7f" dependencies = [ "cbor-smol", "crypto-bigint", @@ -3313,7 +3315,7 @@ dependencies = [ [[package]] name = "trussed-staging" version = "0.1.0" -source = "git+https://github.com/trussed-dev/trussed-staging.git?rev=fdb0dd29bccaf6ec2385b664abc50e4c523ca83e#fdb0dd29bccaf6ec2385b664abc50e4c523ca83e" +source = "git+https://github.com/trussed-dev/trussed-staging.git?rev=97e5557bbfb126c0f0a2367ed928aab4c1469043#97e5557bbfb126c0f0a2367ed928aab4c1469043" dependencies = [ "chacha20poly1305", "delog", diff --git a/Cargo.toml b/Cargo.toml index a38ad7ef..870b84e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,19 +17,19 @@ version = "1.7.0-rc.1" memory-regions = { path = "components/memory-regions" } # forked -admin-app = { git = "https://github.com/Nitrokey/admin-app.git", tag = "v0.1.0-nitrokey.10" } -cbor-smol = { git = "https://github.com/Nitrokey/cbor-smol.git", tag = "v0.4.0-nitrokey.1" } -fido-authenticator = { git = "https://github.com/Nitrokey/fido-authenticator.git", tag = "v0.1.1-nitrokey.12" } +admin-app = { git = "https://github.com/Nitrokey/admin-app.git", rev = "c584a1911ab65670729ea068fe54e0bae7f2459e" } +cbor-smol = { git = "https://github.com/Nitrokey/cbor-smol.git", rev = "bac1ac69dd0117d1f80f3f5e1d3b60ba8987ad70"} +fido-authenticator = { git = "https://github.com/Nitrokey/fido-authenticator.git", rev = "a3757fb1b5d8c9d0485ca7f3524caed7b629dc04" } flexiber = { git = "https://github.com/Nitrokey/flexiber", tag = "0.1.1.nitrokey" } lpc55-hal = { git = "https://github.com/Nitrokey/lpc55-hal", tag = "v0.3.0-nitrokey.2" } serde-indexed = { git = "https://github.com/nitrokey/serde-indexed.git", tag = "v0.1.0-nitrokey.2" } -trussed = { git = "https://github.com/Nitrokey/trussed.git", tag = "v0.1.0-nitrokey.18" } +trussed = { git = "https://github.com/Nitrokey/trussed.git", rev = "371e8f7a07817c2ed57978bd86e3412bd9877647" } # unreleased upstream changes apdu-dispatch = { git = "https://github.com/Nitrokey/apdu-dispatch.git", tag = "v0.1.2-nitrokey.3" } ctap-types = { git = "https://github.com/trussed-dev/ctap-types.git", rev = "a9f8003a1d9f05f9eea39e615b9159bc0613fcb5" } ctaphid-dispatch = { git = "https://github.com/Nitrokey/ctaphid-dispatch.git", tag = "v0.1.1-nitrokey.3" } -littlefs2 = { git = "https://github.com/trussed-dev/littlefs2", rev = "ebd27e49ca321089d01d8c9b169c4aeb58ceeeca" } +littlefs2 = { git = "https://github.com/nitrokey/littlefs2.git", rev = "99b1a9832c46c9097e73ca1fa43e119026e2068f" } usbd-ctaphid = { git = "https://github.com/trussed-dev/usbd-ctaphid.git", rev = "1db2e014f28669bc484c81ab0406c54b16bba33c" } usbd-ccid = { git = "https://github.com/Nitrokey/usbd-ccid", tag = "v0.2.0-nitrokey.1" } p256-cortex-m4 = { git = "https://github.com/ycrypto/p256-cortex-m4.git", rev = "cdb31e12594b4dc1f045b860a885fdc94d96aee2" } @@ -39,12 +39,12 @@ secrets-app = { git = "https://github.com/Nitrokey/trussed-secrets-app", tag = " webcrypt = { git = "https://github.com/nitrokey/nitrokey-websmartcard-rust", rev = "b1502d72035ecde0f16f9fff5c8da06139b90d11" } opcard = { git = "https://github.com/Nitrokey/opcard-rs", rev = "1c844b74aa5bf245cd8223bc63b74b3a1f1f7b0f" } piv-authenticator = { git = "https://github.com/Nitrokey/piv-authenticator", tag = "v0.3.4" } -trussed-staging = { git = "https://github.com/trussed-dev/trussed-staging.git", rev = "fdb0dd29bccaf6ec2385b664abc50e4c523ca83e" } -trussed-auth = { git = "https://github.com/trussed-dev/trussed-auth", rev = "4b8191f248c26cb074cdac887c7f3f48f9c449a4" } +trussed-staging = { git = "https://github.com/trussed-dev/trussed-staging.git", rev = "97e5557bbfb126c0f0a2367ed928aab4c1469043" } trussed-hkdf = { git = "https://github.com/Nitrokey/trussed-hkdf-backend.git", tag = "v0.1.0" } +trussed-auth = { git = "https://github.com/Nitrokey/trussed-auth", rev = "7ad0ab1f592dabb3646840cbb11769a988166fb4" } trussed-rsa-alloc = { git = "https://github.com/trussed-dev/trussed-rsa-backend.git", rev = "9732a9a3e98af72112286afdc9b7174c66c2869a" } trussed-usbip = { git = "https://github.com/Nitrokey/pc-usbip-runner.git", tag = "v0.0.1-nitrokey.3" } -trussed-se050-backend = { git = "https://github.com/Nitrokey/trussed-se050-backend.git", tag = "v0.2.0" } +trussed-se050-backend = { git = "https://github.com/Nitrokey/trussed-se050-backend.git", rev = "393bff2ead093f3a043c3e04ed7a706649f66b7f" } [profile.release] codegen-units = 1 diff --git a/components/apps/Cargo.toml b/components/apps/Cargo.toml index b0e5cd58..66538e20 100644 --- a/components/apps/Cargo.toml +++ b/components/apps/Cargo.toml @@ -62,7 +62,8 @@ webcrypt = ["dep:webcrypt", "backend-auth", "backend-rsa", "backend-webcrypt-hma fido-authenticator = ["dep:fido-authenticator", "usbd-ctaphid"] opcard = ["dep:opcard", "backend-rsa", "backend-auth"] piv-authenticator = ["dep:piv-authenticator", "backend-rsa", "backend-auth"] -se050 = ["dep:se05x", "trussed-se050-backend", "admin-app/se050"] +se050 = ["dep:se05x", "trussed-se050-backend", "admin-app/se050", "se050-migration"] +se050-migration = ["dep:se05x", "trussed-se050-backend"] # backends backend-auth = ["trussed-auth"] diff --git a/components/apps/src/dispatch.rs b/components/apps/src/dispatch.rs index ed626b0f..81e39244 100644 --- a/components/apps/src/dispatch.rs +++ b/components/apps/src/dispatch.rs @@ -40,6 +40,14 @@ use trussed_staging::{ StagingBackend, StagingContext, }; +#[cfg(any( + feature = "fido-authenticator", + feature = "se050-migration", + feature = "backend-auth" +))] +use trussed_staging::manage::Migrator; + +#[cfg(feature = "webcrypt")] #[cfg(feature = "backend-webcrypt-hmacsha256p256")] use webcrypt::hmacsha256p256::{ Backend as HmacSha256P256Backend, BackendContext as HmacSha256P256Context, @@ -92,9 +100,44 @@ fn should_preserve_file(file: &Path) -> bool { } } +pub(crate) const MIGRATION_VERSION_SPACE_EFFICIENCY: u32 = 1; + fn build_staging_backend() -> StagingBackend { let mut backend = StagingBackend::new(); backend.manage.should_preserve_file = |file, _location| should_preserve_file(file); + backend.manage.migrators = &[ + // We first migrate the SE050 since this migration deletes data to make sure that the other + // migrations succeed even on low block availability + #[cfg(feature = "se050-migration")] + Migrator { + migrate: |ifs, _efs| { + trussed_se050_backend::migrate::migrate_remove_all_dat(ifs, &[path!("/opcard")]) + }, + version: MIGRATION_VERSION_SPACE_EFFICIENCY, + }, + #[cfg(feature = "backend-auth")] + Migrator { + migrate: |ifs, _efs| { + trussed_auth::migrate::migrate_remove_dat( + ifs, + &[ + path!("opcard"), + path!("webcrypt"), + path!("secrets"), + path!("piv"), + ], + ) + }, + version: MIGRATION_VERSION_SPACE_EFFICIENCY, + }, + #[cfg(feature = "fido-authenticator")] + Migrator { + migrate: |ifs, _efs| { + fido_authenticator::migrate::migrate_no_rp_dir(ifs, path!("/fido/dat")) + }, + version: MIGRATION_VERSION_SPACE_EFFICIENCY, + }, + ]; backend } diff --git a/components/apps/src/lib.rs b/components/apps/src/lib.rs index db2f1ac8..fe563a1a 100644 --- a/components/apps/src/lib.rs +++ b/components/apps/src/lib.rs @@ -41,6 +41,8 @@ pub struct Config { fido: FidoConfig, #[serde(default, rename = "o", skip_serializing_if = "is_default")] opcard: OpcardConfig, + #[serde(default, rename = "v", skip_serializing_if = "is_default")] + fs_version: u32, } impl admin_app::Config for Config { @@ -74,6 +76,14 @@ impl admin_app::Config for Config { None } } + + fn migration_version(&self) -> Option { + Some(self.fs_version) + } + fn set_migration_version(&mut self, version: u32) -> bool { + self.fs_version = version; + true + } } #[derive(Debug, Default, PartialEq, Deserialize, Serialize)] @@ -82,7 +92,7 @@ pub struct FidoConfig { disable_skip_up_timeout: bool, } -impl admin_app::Config for FidoConfig { +impl FidoConfig { fn field(&mut self, key: &str) -> Option> { match key { "disable_skip_up_timeout" => { @@ -92,6 +102,7 @@ impl admin_app::Config for FidoConfig { } } + #[cfg(feature = "factory-reset")] fn reset_client_id( &self, _key: &str, @@ -132,7 +143,7 @@ impl OpcardConfig { } } -impl admin_app::Config for OpcardConfig { +impl OpcardConfig { fn field(&mut self, key: &str) -> Option> { match key { #[cfg(feature = "se050")] @@ -141,6 +152,7 @@ impl admin_app::Config for OpcardConfig { } } + #[cfg(feature = "factory-reset")] fn reset_client_id( &self, key: &str, @@ -306,6 +318,12 @@ impl Apps { } } + /// Return false if the migration failed. + pub fn ensure_migrated(&mut self) -> bool { + const LATEST_MIGRATION: u32 = dispatch::MIGRATION_VERSION_SPACE_EFFICIENCY; + self.admin.migrate(LATEST_MIGRATION).is_ok() + } + fn admin_app( runner: &R, make_client: impl FnOnce( @@ -337,6 +355,7 @@ impl Apps { data.status(), ) }); + (app, data.init_status) } @@ -369,27 +388,31 @@ impl Apps { let mut apps: Vec<&mut dyn ApduApp, 7> = Default::default(); + let migrated_successfuly = self.ensure_migrated(); + // App 1: ndef #[cfg(feature = "ndef-app")] apps.push(&mut self.ndef).ok().unwrap(); - // App 2: secrets - #[cfg(feature = "secrets-app")] - apps.push(&mut self.oath).ok().unwrap(); + if migrated_successfuly { + // App 2: secrets + #[cfg(feature = "secrets-app")] + apps.push(&mut self.oath).ok().unwrap(); - // App 3: opcard - #[cfg(feature = "opcard")] - if let Some(opcard) = &mut self.opcard { - apps.push(opcard).ok().unwrap(); - } + // App 3: opcard + #[cfg(feature = "opcard")] + if let Some(opcard) = &mut self.opcard { + apps.push(opcard).ok().unwrap(); + } - // App 4: piv - #[cfg(feature = "piv-authenticator")] - apps.push(&mut self.piv).ok().unwrap(); + // App 4: piv + #[cfg(feature = "piv-authenticator")] + apps.push(&mut self.piv).ok().unwrap(); - // App 5: fido - #[cfg(all(feature = "fido-authenticator", not(feature = "webcrypt")))] - apps.push(&mut self.fido).ok().unwrap(); + // App 5: fido + #[cfg(all(feature = "fido-authenticator", not(feature = "webcrypt")))] + apps.push(&mut self.fido).ok().unwrap(); + } // App 6: admin apps.push(&mut self.admin).ok().unwrap(); @@ -407,18 +430,24 @@ impl Apps { { let mut apps: Vec<&mut dyn CtaphidApp<'static>, 4> = Default::default(); - // App 1: webcrypt or fido - #[cfg(feature = "webcrypt")] - apps.push(&mut self.webcrypt).ok().unwrap(); - #[cfg(all(feature = "fido-authenticator", not(feature = "webcrypt")))] - apps.push(&mut self.fido).ok().unwrap(); + let migrated_successfuly = self.ensure_migrated(); + + if migrated_successfuly { + // App 1: webcrypt or fido + #[cfg(feature = "webcrypt")] + apps.push(&mut self.webcrypt).ok().unwrap(); + #[cfg(all(feature = "fido-authenticator", not(feature = "webcrypt")))] + apps.push(&mut self.fido).ok().unwrap(); + } // App 2: admin apps.push(&mut self.admin).ok().unwrap(); - // App 3: secrets - #[cfg(feature = "secrets-app")] - apps.push(&mut self.oath).ok().unwrap(); + if migrated_successfuly { + // App 3: secrets + #[cfg(feature = "secrets-app")] + apps.push(&mut self.oath).ok().unwrap(); + } // App 4: provisioner #[cfg(feature = "provisioner-app")] @@ -462,7 +491,7 @@ impl trussed_usbip::Apps<'static, Client, Dispatch> for Apps { trait App: Sized { /// additional data needed by this Trussed app type Data; - type Config: admin_app::Config; + type Config; /// the desired client ID const CLIENT_ID: &'static str; @@ -845,6 +874,7 @@ mod tests { #[cfg(feature = "se050")] use_se050_backend: true, }, + fs_version: 1, }; let data: Bytes<1024> = cbor_serialize_bytes(&config).unwrap(); // littlefs2 is most efficient with files < 1/4 of the block size. The block sizes are 512