Skip to content

Commit 6c2cb25

Browse files
Merge pull request #139 from Nitrokey/data-encryption
Complete request for data encryption
2 parents e569230 + f2a35b8 commit 6c2cb25

File tree

11 files changed

+836
-278
lines changed

11 files changed

+836
-278
lines changed

Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ trussed = "0.1.0"
3434
trussed-rsa-alloc = { version = "0.1.0", optional = true }
3535
serde_repr = "0.1"
3636
hex-literal = "0.3.4"
37-
trussed-auth = "0.1.0"
37+
trussed-auth = "0.2.1"
3838

3939
# optional dependencies
4040
apdu-dispatch = { version = "0.1", optional = true }
@@ -85,8 +85,8 @@ log-error = []
8585
interchange = { git = "https://github.com/trussed-dev/interchange", rev = "fe5633466640e1e9a8c06d9b5dd1d0af08c272af" }
8686
littlefs2 = { git = "https://github.com/Nitrokey/littlefs2", tag = "v0.3.2-nitrokey-2" }
8787
p256-cortex-m4 = { git = "https://github.com/Nitrokey/p256-cortex-m4", tag = "v0.1.0-alpha.6-nitrokey-1" }
88-
trussed = { git = "https://github.com/Nitrokey/trussed" , tag = "v0.1.0-nitrokey.8" }
89-
trussed-auth = { git = "https://github.com/trussed-dev/trussed-auth.git", tag= "v0.1.0"}
88+
trussed = { git = "https://github.com/Nitrokey/trussed" , tag = "v0.1.0-nitrokey.9" }
89+
trussed-auth = { git = "https://github.com/trussed-dev/trussed-auth.git", tag= "v0.2.1"}
9090
trussed-rsa-alloc = { git = "https://github.com/Nitrokey/trussed-rsa-backend", rev = "311d2366f99cc300b03d61e7f6a0a07abd3e8700" }
9191

9292
[package.metadata.docs.rs]

src/command.rs

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,7 @@ fn reset_retry_conter<const R: usize, T: trussed::Client + AuthClient>(
553553
}
554554

555555
fn reset_retry_conter_with_p3<const R: usize, T: trussed::Client + AuthClient>(
556-
ctx: LoadedContext<'_, R, T>,
556+
mut ctx: LoadedContext<'_, R, T>,
557557
) -> Result<(), Status> {
558558
if ctx.data.len() < MIN_LENGTH_USER_PIN || ctx.data.len() > MAX_PIN_LENGTH {
559559
warn!(
@@ -568,13 +568,7 @@ fn reset_retry_conter_with_p3<const R: usize, T: trussed::Client + AuthClient>(
568568
}
569569

570570
ctx.state
571-
.persistent
572-
.set_pin(
573-
ctx.backend.client_mut(),
574-
ctx.options.storage,
575-
ctx.data,
576-
Password::Pw1,
577-
)
571+
.reset_user_code_with_pw3(ctx.backend.client_mut(), ctx.options.storage, ctx.data)
578572
.map_err(|_err| {
579573
error!("Failed to change PIN: {_err}");
580574
Status::UnspecifiedNonpersistentExecutionError
@@ -601,7 +595,7 @@ fn reset_retry_conter_with_code<const R: usize, T: trussed::Client + AuthClient>
601595
let res = ctx
602596
.state
603597
.check_pin(ctx.backend.client_mut(), old, Password::ResetCode);
604-
match res {
598+
let rc_key = match res {
605599
Err(Error::InvalidPin) => {
606600
return Err(Status::RemainingRetries(
607601
ctx.state
@@ -613,26 +607,22 @@ fn reset_retry_conter_with_code<const R: usize, T: trussed::Client + AuthClient>
613607
error!("Failed to check reset code: {_err:?}");
614608
return Err(Status::UnspecifiedNonpersistentExecutionError);
615609
}
616-
Ok(_reset_kek) => {}
617-
}
610+
Ok(rc_key) => rc_key,
611+
};
618612

619613
if new.len() > MAX_PIN_LENGTH || new.len() < MIN_LENGTH_USER_PIN {
620614
warn!("Attempt to set resetting code with invalid length");
621615
return Err(Status::IncorrectDataParameter);
622616
}
623617

624618
ctx.state
625-
.persistent
626-
.set_pin(
627-
ctx.backend.client_mut(),
628-
ctx.options.storage,
629-
new,
630-
Password::Pw1,
631-
)
619+
.reset_user_code_with_rc(ctx.backend.client_mut(), ctx.options.storage, new, rc_key)
632620
.map_err(|_err| {
633621
error!("Failed to change PIN: {_err:?}");
634622
Status::UnspecifiedNonpersistentExecutionError
635-
})
623+
})?;
624+
syscall!(ctx.backend.client_mut().delete(rc_key));
625+
Ok(())
636626
}
637627

638628
// § 7.2.5

src/command/data.rs

Lines changed: 120 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@ use hex_literal::hex;
66
use iso7816::Status;
77
use trussed::{
88
syscall, try_syscall,
9-
types::{KeySerialization, Mechanism},
9+
types::{KeyId, KeySerialization, Mechanism},
1010
};
1111
use trussed_auth::AuthClient;
1212

13+
const CHACHA_NONCE_SIZE: usize = 12;
14+
const CHACHA_TAG_SIZE: usize = 16;
15+
1316
use crate::{
1417
card::{Context, LoadedContext, Options},
1518
command::{GetDataMode, Password, PutDataMode, Tag},
@@ -375,8 +378,12 @@ impl GetDataObject {
375378
Self::KdfDo => get_arbitrary_do(context, ArbitraryDO::KdfDo)?,
376379
Self::PrivateUse1 => get_arbitrary_do(context, ArbitraryDO::PrivateUse1)?,
377380
Self::PrivateUse2 => get_arbitrary_do(context, ArbitraryDO::PrivateUse2)?,
378-
Self::PrivateUse3 => get_arbitrary_do(context, ArbitraryDO::PrivateUse3)?,
379-
Self::PrivateUse4 => get_arbitrary_do(context, ArbitraryDO::PrivateUse4)?,
381+
Self::PrivateUse3 => {
382+
get_arbitrary_user_enc_do(context.load_state()?, ArbitraryDO::PrivateUse3)?
383+
}
384+
Self::PrivateUse4 => {
385+
get_arbitrary_admin_enc_do(context.load_state()?, ArbitraryDO::PrivateUse4)?
386+
}
380387
Self::CardHolderCertificate => cardholder_cert(context)?,
381388
Self::SecureMessagingCertificate => return Err(Status::SecureMessagingNotSupported),
382389
Self::CardHolderRelatedData
@@ -811,6 +818,54 @@ fn get_arbitrary_do<const R: usize, T: trussed::Client + AuthClient>(
811818
ctx.reply.expand(&data)
812819
}
813820

821+
fn get_arbitrary_enc_do<const R: usize, T: trussed::Client + AuthClient>(
822+
mut ctx: LoadedContext<'_, R, T>,
823+
obj: ArbitraryDO,
824+
key: KeyId,
825+
) -> Result<(), Status> {
826+
let data = obj
827+
.load(ctx.backend.client_mut(), ctx.options.storage)
828+
.map_err(|_| Status::UnspecifiedNonpersistentExecutionError)?;
829+
if data.is_empty() {
830+
return Ok(());
831+
}
832+
let (data, tag) = data.split_at(data.len() - CHACHA_TAG_SIZE);
833+
let (data, nonce) = data.split_at(data.len() - CHACHA_NONCE_SIZE);
834+
let decrypted = syscall!(ctx.backend.client_mut().decrypt(
835+
Mechanism::Chacha8Poly1305,
836+
key,
837+
data,
838+
&[],
839+
nonce,
840+
tag
841+
))
842+
.plaintext
843+
.ok_or(Status::UnspecifiedNonpersistentExecutionError)?;
844+
ctx.reply.expand(&decrypted)
845+
}
846+
847+
/// Get an arbitrary DO encrypted with the user key
848+
fn get_arbitrary_user_enc_do<const R: usize, T: trussed::Client + AuthClient>(
849+
ctx: LoadedContext<'_, R, T>,
850+
obj: ArbitraryDO,
851+
) -> Result<(), Status> {
852+
let Some(k) = ctx.state.volatile.other_verified_kek() else {
853+
return Err(Status::SecurityStatusNotSatisfied);
854+
};
855+
get_arbitrary_enc_do(ctx, obj, k)
856+
}
857+
858+
/// Get an arbitrary DO encrypted with the admin key
859+
fn get_arbitrary_admin_enc_do<const R: usize, T: trussed::Client + AuthClient>(
860+
ctx: LoadedContext<'_, R, T>,
861+
obj: ArbitraryDO,
862+
) -> Result<(), Status> {
863+
let Some(k) = ctx.state.volatile.admin_kek() else {
864+
return Err(Status::SecurityStatusNotSatisfied);
865+
};
866+
get_arbitrary_enc_do(ctx, obj, k)
867+
}
868+
814869
// § 7.2.8
815870
pub fn put_data<const R: usize, T: trussed::Client + AuthClient>(
816871
mut context: Context<'_, R, T>,
@@ -889,7 +944,7 @@ enum_subset! {
889944
impl PutDataObject {
890945
fn write_perm(&self) -> PermissionRequirement {
891946
match self {
892-
Self::PrivateUse2 | Self::PrivateUse4 => PermissionRequirement::User,
947+
Self::PrivateUse1 | Self::PrivateUse3 => PermissionRequirement::User,
893948
_ => PermissionRequirement::Admin,
894949
}
895950
}
@@ -901,8 +956,12 @@ impl PutDataObject {
901956
match self {
902957
Self::PrivateUse1 => put_arbitrary_do(ctx, ArbitraryDO::PrivateUse1)?,
903958
Self::PrivateUse2 => put_arbitrary_do(ctx, ArbitraryDO::PrivateUse2)?,
904-
Self::PrivateUse3 => put_arbitrary_do(ctx, ArbitraryDO::PrivateUse3)?,
905-
Self::PrivateUse4 => put_arbitrary_do(ctx, ArbitraryDO::PrivateUse4)?,
959+
Self::PrivateUse3 => {
960+
put_arbitrary_user_enc_do(ctx.load_state()?, ArbitraryDO::PrivateUse3)?
961+
}
962+
Self::PrivateUse4 => {
963+
put_arbitrary_admin_enc_do(ctx.load_state()?, ArbitraryDO::PrivateUse4)?
964+
}
906965
Self::LoginData => put_arbitrary_do(ctx, ArbitraryDO::LoginData)?,
907966
Self::ExtendedHeaderList => {
908967
super::private_key_template::put_private_key_template(ctx.load_state()?)?
@@ -954,7 +1013,7 @@ fn put_cardholder_cert<const R: usize, T: trussed::Client + AuthClient>(
9541013
const AES256_KEY_LEN: usize = 32;
9551014

9561015
fn put_enc_dec_key<const R: usize, T: trussed::Client + AuthClient>(
957-
ctx: LoadedContext<'_, R, T>,
1016+
mut ctx: LoadedContext<'_, R, T>,
9581017
) -> Result<(), Status> {
9591018
if ctx.data.len() != AES256_KEY_LEN {
9601019
warn!(
@@ -976,23 +1035,18 @@ fn put_enc_dec_key<const R: usize, T: trussed::Client + AuthClient>(
9761035
})?
9771036
.key;
9781037

979-
let old_key = ctx
980-
.state
981-
.persistent
982-
.set_aes_key_id(Some(new_key), ctx.backend.client_mut(), ctx.options.storage)
1038+
ctx.state
1039+
.set_aes_key(new_key, ctx.backend.client_mut(), ctx.options.storage)
9831040
.map_err(|_err| {
9841041
error!("Failed to set new key: {_err:?}");
9851042
Status::UnspecifiedNonpersistentExecutionError
9861043
})?;
987-
if let Some(old_key) = old_key {
988-
syscall!(ctx.backend.client_mut().delete(old_key));
989-
}
9901044

9911045
Ok(())
9921046
}
9931047

9941048
fn put_resetting_code<const R: usize, T: trussed::Client + AuthClient>(
995-
ctx: LoadedContext<'_, R, T>,
1049+
mut ctx: LoadedContext<'_, R, T>,
9961050
) -> Result<(), Status> {
9971051
if ctx.data.is_empty() {
9981052
info!("Removing resetting code");
@@ -1014,13 +1068,7 @@ fn put_resetting_code<const R: usize, T: trussed::Client + AuthClient>(
10141068
}
10151069

10161070
ctx.state
1017-
.persistent
1018-
.set_pin(
1019-
ctx.backend.client_mut(),
1020-
ctx.options.storage,
1021-
ctx.data,
1022-
Password::ResetCode,
1023-
)
1071+
.set_reset_code(ctx.backend.client_mut(), ctx.options.storage, ctx.data)
10241072
.map_err(|_err| {
10251073
error!("Failed to change resetting code: {_err}");
10261074
Status::UnspecifiedNonpersistentExecutionError
@@ -1200,6 +1248,56 @@ fn put_alg_attributes_aut<const R: usize, T: trussed::Client + AuthClient>(
12001248
.map_err(|_| Status::UnspecifiedNonpersistentExecutionError)
12011249
}
12021250

1251+
fn put_arbitrary_admin_enc_do<const R: usize, T: trussed::Client + AuthClient>(
1252+
ctx: LoadedContext<'_, R, T>,
1253+
obj: ArbitraryDO,
1254+
) -> Result<(), Status> {
1255+
let Some(k) = ctx.state.volatile.admin_kek() else {
1256+
return Err(Status::SecurityStatusNotSatisfied);
1257+
};
1258+
put_arbitrary_enc_do(ctx, obj, k)
1259+
}
1260+
fn put_arbitrary_user_enc_do<const R: usize, T: trussed::Client + AuthClient>(
1261+
ctx: LoadedContext<'_, R, T>,
1262+
obj: ArbitraryDO,
1263+
) -> Result<(), Status> {
1264+
let Some(k) =ctx.state.volatile.other_verified_kek() else {
1265+
return Err(Status::SecurityStatusNotSatisfied);
1266+
};
1267+
put_arbitrary_enc_do(ctx, obj, k)
1268+
}
1269+
1270+
fn put_arbitrary_enc_do<const R: usize, T: trussed::Client + AuthClient>(
1271+
ctx: LoadedContext<'_, R, T>,
1272+
obj: ArbitraryDO,
1273+
key: KeyId,
1274+
) -> Result<(), Status> {
1275+
if ctx.data.len() + CHACHA_NONCE_SIZE + CHACHA_TAG_SIZE > MAX_GENERIC_LENGTH {
1276+
return Err(Status::WrongLength);
1277+
}
1278+
let mut encrypted = syscall!(ctx.backend.client_mut().encrypt(
1279+
Mechanism::Chacha8Poly1305,
1280+
key,
1281+
ctx.data,
1282+
&[],
1283+
None
1284+
));
1285+
encrypted
1286+
.ciphertext
1287+
.extend_from_slice(&encrypted.nonce)
1288+
.map_err(|_| Status::NotEnoughMemory)?;
1289+
encrypted
1290+
.ciphertext
1291+
.extend_from_slice(&encrypted.tag)
1292+
.map_err(|_| Status::NotEnoughMemory)?;
1293+
obj.save(
1294+
ctx.backend.client_mut(),
1295+
ctx.options.storage,
1296+
&encrypted.ciphertext,
1297+
)
1298+
.map_err(|_| Status::UnspecifiedPersistentExecutionError)
1299+
}
1300+
12031301
fn put_arbitrary_do<const R: usize, T: trussed::Client + AuthClient>(
12041302
ctx: Context<'_, R, T>,
12051303
obj: ArbitraryDO,

0 commit comments

Comments
 (0)