Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: add basic encrypted key management tests #38

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 104 additions & 1 deletion src/tests/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,12 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use std::borrow::Cow;
use std::iter;

use crate::keytypes::User;
use crate::keytype::KeyPayload;
use crate::keytypes::encrypted::{Format, MasterKeyType, Payload};
use crate::keytypes::{Encrypted, User};
use crate::{Keyring, KeyringSerial, SpecialKeyring};

use super::utils::kernel::*;
Expand Down Expand Up @@ -129,3 +132,103 @@ fn add_key_to_session() {
assert_eq!(new_payload, new_expected);
keyring.unlink_key(&key).unwrap();
}

#[test]
fn add_encrypted_key_to_session() {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather that keytype-specific tests go into src/keytypes/TYPE.rs than at the operation level.

let mut keyring = Keyring::attach_or_create(SpecialKeyring::Session).unwrap();
let master_key = keyring
.add_key::<User, _, _>("foo", "bar".as_bytes())
.unwrap();
let new_payload = Payload::New {
format: Some(Format::default()),
keytype: MasterKeyType::User,
description: Cow::Borrowed("foo"),
keylen: 32,
};

let mut enc_key = keyring
.add_key::<Encrypted, _, _>("baz", new_payload)
.unwrap();

// A normal payload update fails
assert_eq!(
enc_key.update("qux".as_bytes()),
Err(errno::Errno(libc::EINVAL))
);

keyring.unlink_key(&enc_key).unwrap();
keyring.unlink_key(&master_key).unwrap();
}

#[test]
#[should_panic(
expected = "called `Result::unwrap()` on an `Err` value: Errno { code: 22, description: Some(\"Invalid argument\") }"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #34 for the preferred method for checking for expected errors. The main issue with this strategy is that it doesn't check which unwrap caused this problem.

)]
fn load_encrypted_key_to_session() {
let mut keyring = Keyring::attach_or_create(SpecialKeyring::Session).unwrap();
let master_key = keyring
.add_key::<User, _, _>("foo", "bar".as_bytes())
.unwrap();
let new_payload = Payload::New {
format: Some(Format::default()),
keytype: MasterKeyType::User,
description: Cow::Borrowed("foo"),
keylen: 32,
};
let enc_key = keyring
.add_key::<Encrypted, _, _>("baz", new_payload)
.unwrap();
let buf = enc_key.read().unwrap();

let load_payload = Payload::Load {
blob: buf.clone(),
};

keyring.unlink_key(&enc_key).unwrap();

// This should not panic but currently does due to the use
// of ByteBuf when encoding the load payload.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason ByteBufs LowerHex is used for the Load payload type? AFAIK that is what is causing this test to fail.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/torvalds/linux/blob/master/Documentation/security/keys/trusted-encrypted.rst

All user level blobs, are displayed and loaded in hex ascii for convenience, and are integrity verified.

In code, it is read here and parsed here by this function which only supports lowercase ASCII hex.

Copy link
Contributor Author

@dlrobertson dlrobertson Jan 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I didn't do a good job of explaining the issue I hit.

https://github.com/torvalds/linux/blob/master/security/keys/encrypted-keys/encrypted.c#L162

* load [<format>] <master-key name> <decrypted data length>
*     <encrypted iv + data>

The key format, master key description, and the decrypted data length are parsed before the hex encoded data.

The current payload encoding for the load payload encodes everything but the key command as lower-case hex. This includes the format, master key, and decrypted data length, which AIUI should not be encoded as lower-case hex (why the should_panic test fails when it AFAIK should pass).

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh. Let's fix that in the Payload enum representation. I may have mixed up which docs/code I was looking at when making the payload type here.

Tests for the various keytypes was on my list after finishing #34, but the CI issues burned me out for a while on that :/ .

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose a patch to fix the documentation for the load format should also be made:

keyctl add encrypted name "load hex_blob" ring

let load_key = keyring
.add_key::<Encrypted, _, _>("qux", load_payload)
.unwrap();

keyring.unlink_key(&load_key).unwrap();
keyring.unlink_key(&master_key).unwrap();
}

#[test]
fn update_encrypted_key_in_session() {
let mut keyring = Keyring::attach_or_create(SpecialKeyring::Session).unwrap();
let old_master_key = keyring
.add_key::<User, _, _>("foo", "bar".as_bytes())
.unwrap();
let new_master_key = keyring
.add_key::<User, _, _>("bar", "foo".as_bytes())
.unwrap();
let new_payload = Payload::New {
format: Some(Format::default()),
keytype: MasterKeyType::User,
description: Cow::Borrowed("foo"),
keylen: 32,
};

let mut enc_key = keyring
.add_key::<Encrypted, _, _>("baz", new_payload)
.unwrap();

// A normal payload update fails
assert_eq!(
enc_key.update("qux".as_bytes()),
Err(errno::Errno(libc::EINVAL))
);

let update_payload = Payload::Update {
keytype: MasterKeyType::User,
description: Cow::Borrowed("bar"),
};
enc_key.update(update_payload.payload()).unwrap();

keyring.unlink_key(&enc_key).unwrap();
keyring.unlink_key(&old_master_key).unwrap();
keyring.unlink_key(&new_master_key).unwrap();
}