Skip to content

Commit

Permalink
Encrypt the AES key
Browse files Browse the repository at this point in the history
  • Loading branch information
sosthene-nitrokey committed Mar 28, 2023
1 parent baf0bdf commit 68787ce
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 40 deletions.
11 changes: 3 additions & 8 deletions src/command/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1013,7 +1013,7 @@ fn put_cardholder_cert<const R: usize, T: trussed::Client + AuthClient>(
const AES256_KEY_LEN: usize = 32;

fn put_enc_dec_key<const R: usize, T: trussed::Client + AuthClient>(
ctx: LoadedContext<'_, R, T>,
mut ctx: LoadedContext<'_, R, T>,
) -> Result<(), Status> {
if ctx.data.len() != AES256_KEY_LEN {
warn!(
Expand All @@ -1035,17 +1035,12 @@ fn put_enc_dec_key<const R: usize, T: trussed::Client + AuthClient>(
})?
.key;

let old_key = ctx
.state
.persistent
.set_aes_key_id(Some(new_key), ctx.backend.client_mut(), ctx.options.storage)
ctx.state
.set_aes_key(new_key, ctx.backend.client_mut(), ctx.options.storage)
.map_err(|_err| {
error!("Failed to set new key: {_err:?}");
Status::UnspecifiedNonpersistentExecutionError
})?;
if let Some(old_key) = old_key {
syscall!(ctx.backend.client_mut().delete(old_key));
}

Ok(())
}
Expand Down
29 changes: 16 additions & 13 deletions src/command/pso.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,10 +358,14 @@ fn decrypt_ec<const R: usize, T: trussed::Client + AuthClient>(
fn decipher_aes<const R: usize, T: trussed::Client + AuthClient>(
mut ctx: LoadedContext<'_, R, T>,
) -> Result<(), Status> {
let key_id = ctx.state.persistent.aes_key().ok_or_else(|| {
warn!("Attempt to decipher with AES and no key set");
Status::ConditionsOfUseNotSatisfied
})?;
let key_id = ctx
.state
.volatile
.aes_key_id(ctx.backend.client_mut(), ctx.options.storage)
.map_err(|_err| {
warn!("Failed to load aes key: {:?}", _err);
Status::ConditionsOfUseNotSatisfied
})?;

if (ctx.data.len() - 1) % 16 != 0 {
warn!("Attempt to decipher with AES with length not a multiple of block size");
Expand All @@ -387,15 +391,14 @@ fn decipher_aes<const R: usize, T: trussed::Client + AuthClient>(
pub fn encipher<const R: usize, T: trussed::Client + AuthClient>(
mut ctx: LoadedContext<'_, R, T>,
) -> Result<(), Status> {
if !ctx.state.volatile.other_verified() {
warn!("Attempt to encipher without PW1 verified");
return Err(Status::SecurityStatusNotSatisfied);
}

let key_id = ctx.state.persistent.aes_key().ok_or_else(|| {
warn!("Attempt to decipher with AES and no key set");
Status::ConditionsOfUseNotSatisfied
})?;
let key_id = ctx
.state
.volatile
.aes_key_id(ctx.backend.client_mut(), ctx.options.storage)
.map_err(|_err| {
warn!("Failed to load aes key: {:?}", _err);
Status::ConditionsOfUseNotSatisfied
})?;

if ctx.data.len() % 16 != 0 {
warn!("Attempt to encipher with AES with length not a multiple of block size");
Expand Down
68 changes: 49 additions & 19 deletions src/state.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (C) 2022 Nitrokey GmbH
// SPDX-License-Identifier: LGPL-3.0-only

use core::mem::{swap, take};
use core::mem::take;

use heapless_bytes::Bytes;
use hex_literal::hex;
Expand Down Expand Up @@ -39,6 +39,7 @@ pub const MAX_GENERIC_LENGTH_BE: [u8; 2] = (MAX_GENERIC_LENGTH as u16).to_be_byt
pub const SIGNING_KEY_PATH: &str = "signing_key.bin";
pub const DEC_KEY_PATH: &str = "conf_key.bin";
pub const AUTH_KEY_PATH: &str = "auth_key.bin";
pub const AES_KEY_PATH: &str = "aes_key.bin";

macro_rules! enum_u8 {
(
Expand Down Expand Up @@ -435,6 +436,26 @@ impl<'a> LoadedState<'a> {
Ok(())
}

pub fn set_aes_key<T: trussed::Client + AuthClient>(
&mut self,
new: KeyId,
client: &mut T,
storage: Location,
) -> Result<(), Error> {
self.volatile.user.0.clear_aes_cached(client);
let user_kek = self.get_user_key(client, storage)?;
syscall!(client.wrap_to_file(
Mechanism::Chacha8Poly1305,
user_kek,
new,
PathBuf::from(AES_KEY_PATH),
storage,
AES_KEY_PATH.as_bytes()
));
syscall!(client.delete(new));
Ok(())
}

/// New contains (private key, (public key, KeyOrigin))
pub fn set_key<T: trussed::Client + AuthClient>(
&mut self,
Expand Down Expand Up @@ -522,7 +543,6 @@ pub struct Persistent {
confidentiality_key: Option<(KeyId, KeyOrigin)>,
/// (public_key, origin)
aut_key: Option<(KeyId, KeyOrigin)>,
aes_key: Option<KeyId>,
sign_alg: SignatureAlgorithm,
dec_alg: DecryptionAlgorithm,
aut_alg: AuthenticationAlgorithm,
Expand Down Expand Up @@ -564,7 +584,6 @@ impl Persistent {
signing_key: None,
confidentiality_key: None,
aut_key: None,
aes_key: None,
sign_alg: SignatureAlgorithm::default(),
dec_alg: DecryptionAlgorithm::default(),
aut_alg: AuthenticationAlgorithm::default(),
Expand Down Expand Up @@ -942,21 +961,6 @@ impl Persistent {
}
}

pub fn aes_key(&self) -> &Option<KeyId> {
&self.aes_key
}

pub fn set_aes_key_id(
&mut self,
mut new: Option<KeyId>,
client: &mut impl trussed::Client,
storage: Location,
) -> Result<Option<KeyId>, Error> {
swap(&mut self.aes_key, &mut new);
self.save(client, storage)?;
Ok(new)
}

pub fn delete_key(
&mut self,
ty: KeyType,
Expand Down Expand Up @@ -1015,6 +1019,7 @@ struct UserKeys {
sign: Option<KeyId>,
dec: Option<KeyId>,
aut: Option<KeyId>,
aes: Option<KeyId>,
}

impl UserKeys {
Expand All @@ -1024,7 +1029,7 @@ impl UserKeys {
}

fn clear(&mut self, client: &mut impl trussed::Client) {
for k in [&mut self.sign, &mut self.dec, &mut self.aut]
for k in [&mut self.sign, &mut self.dec, &mut self.aut, &mut self.aes]
.into_iter()
.flat_map(Option::take)
{
Expand Down Expand Up @@ -1174,6 +1179,16 @@ impl UserVerifiedInner {
}
}

fn clear_aes_cached(&mut self, client: &mut impl trussed::Client) {
let Some(cache) = self.cache_mut() else {
return;
};

if let Some(k) = cache.aes {
syscall!(client.delete(k));
}
}

fn clear_sign(&mut self, client: &mut impl trussed::Client) {
match self {
Self::Sign(_k, _cache) => self.clear(client),
Expand Down Expand Up @@ -1272,6 +1287,21 @@ impl Volatile {
Ok(unwrapped_key)
}

pub fn aes_key_id(
&mut self,
client: &mut impl trussed::Client,
storage: Location,
) -> Result<KeyId, Status> {
match &mut self.user.0 {
UserVerifiedInner::None | UserVerifiedInner::Sign(_, _) => {
Err(Status::ConditionsOfUseNotSatisfied)
}
UserVerifiedInner::Other(user_kek, cache)
| UserVerifiedInner::OtherAndSign(user_kek, cache) => {
Self::load_or_get_key(client, *user_kek, &mut cache.aes, AES_KEY_PATH, storage)
}
}
}
/// Returns the requested key
pub fn key_id(
&mut self,
Expand Down

0 comments on commit 68787ce

Please sign in to comment.