extern crate alloc;
use alloc::{collections::BTreeSet, vec, vec::Vec};
use core::ops::Add;
use spideroak_crypto::{
aead::{Aead, OpenError},
csprng::Random,
default::Rng,
generic_array::ArrayLength,
hpke::HpkeError,
typenum::{Sum, U64},
};
use super::{assert_ct_eq, assert_ct_ne};
use crate::{
afc,
apq::{
EncryptedTopicKey, ReceiverSecretKey, Sender, SenderSecretKey, SenderSigningKey, Topic,
TopicKey, Version,
},
aranya::{DeviceId, Encap, EncryptionKey, IdentityKey, SigningKey as DeviceSigningKey},
ciphersuite::CipherSuite,
engine::Engine,
error::Error,
groupkey::{Context, EncryptedGroupKey, GroupKey},
id::{IdExt as _, Identified as _},
policy::{CmdId, GroupId, LabelId, PolicyId},
tls,
util::cbor,
};
#[macro_export]
macro_rules! for_each_engine_test {
($callback:ident) => {
$crate::__apply! {
$callback,
test_simple_device_signing_key_sign,
test_simple_seal_group_key,
test_simple_wrap_group_key,
test_simple_wrap_device_identity_key,
test_simple_export_device_identity_key,
test_simple_identity_key_sign,
test_simple_wrap_device_signing_key,
test_simple_export_device_signing_key,
test_simple_wrap_device_encryption_key,
test_simple_export_device_encryption_key,
test_group_key_seal,
test_group_key_open_wrong_key,
test_group_key_open_wrong_context,
test_group_key_open_bad_ciphertext,
test_encrypted_group_key_encode,
test_simple_sender_signing_key_sign,
test_simple_seal_topic_key,
test_simple_wrap_device_sender_secret_key,
test_simple_wrap_device_sender_signing_key,
test_simple_wrap_device_receiver_secret_key,
test_topic_key_seal,
test_topic_key_open_wrong_key,
test_topic_key_open_wrong_context,
test_topic_key_open_bad_ciphertext,
test_afc_same_seal_key_open_key,
test_afc_different_seal_key_open_key,
test_afc_seal_key_monotonic_seq_number,
test_afc_seal_key_seq_number_exhausted,
test_afc_open_key_seq_number_exhausted,
test_afc_open_key_wrong_seq_number,
test_afc_open_key_wrong_auth_data,
test_afc_derive_uni_key,
test_afc_derive_uni_key_different_labels,
test_afc_derive_uni_key_different_device_ids,
test_afc_derive_uni_key_different_cmd_ids,
test_afc_derive_uni_key_different_keys,
test_afc_derive_uni_seal_key_same_device_id,
test_afc_derive_uni_open_key_same_device_id,
test_afc_wrap_uni_author_secret,
test_tls_psk_different_suites,
test_tls_psk_different_policy_ids,
test_tls_psk_different_contexts,
test_tls_psk_different_groups,
test_tls_psk_seed_simple_wrap,
test_tls_psk_seed_seal_open,
test_tls_psk_seed_open_wrong_peer_pk,
test_tls_psk_seed_open_wrong_sk,
test_tls_psk_seed_open_wrong_group,
test_tls_psk_seed_open_wrong_ciphertext,
test_tls_psk_seed_open_wrong_tag,
}
};
}
pub use for_each_engine_test;
#[macro_export]
macro_rules! test_engine {
($name:ident, || -> $engine:ty { $($args:tt)+ }) => {
mod $name {
#[allow(unused_imports)]
use super::*;
$crate::test_engine!(|| -> $engine { $($args)+ });
}
};
(|| -> $engine:ty { $($args:tt)+ }) => {
$crate::test_util::test_ciphersuite!(ciphersuite, <$engine as $crate::engine::Engine>::CS);
macro_rules! __engine_test {
($test:ident) => {
#[test]
fn $test() {
$crate::test_util::engine::$test(&mut { $($args)+ });
}
};
}
$crate::for_each_engine_test!(__engine_test);
};
}
pub use test_engine;
pub fn test_simple_device_signing_key_sign<E: Engine>(eng: &E) {
const MSG: &[u8] = b"hello, world!";
const CONTEXT: &[u8] = b"test_simple_device_signing_key_sign";
let sign_key = DeviceSigningKey::<E::CS>::new(eng);
let sig = sign_key
.sign(MSG, CONTEXT)
.expect("unable to create signature");
sign_key
.public()
.expect("sender signing key should be valid")
.verify(MSG, CONTEXT, &sig)
.expect("the signature should be valid");
sign_key
.public()
.expect("sender signing key should be valid")
.verify(MSG, b"wrong context", &sig)
.expect_err("should fail with wrong context");
let wrong_sig = sign_key
.sign(b"different", b"signature")
.expect("should not fail to create signature");
sign_key
.public()
.expect("sender signing key should be valid")
.verify(MSG, CONTEXT, &wrong_sig)
.expect_err("should fail with wrong signature");
}
pub fn test_simple_seal_group_key<E: Engine>(eng: &E) {
let enc_key = EncryptionKey::<E::CS>::new(eng);
let group = GroupId::default();
let want = GroupKey::new(eng);
let (enc, ciphertext) = enc_key
.public()
.expect("public encryption key should be valid")
.seal_group_key(eng, &want, group)
.expect("unable to encrypt `GroupKey`");
let got = enc_key
.open_group_key(&enc, ciphertext, group)
.expect("unable to decrypt `GroupKey`");
assert_eq!(want.id(), got.id());
}
pub fn test_simple_wrap_group_key<E: Engine>(eng: &E) {
let want = GroupKey::new(eng);
let bytes = cbor::to_allocvec(
&eng.wrap(want.clone())
.expect("should be able to wrap `GroupKey`"),
)
.expect("should be able to encode wrapped `GroupKey`");
let wrapped =
cbor::from_bytes(&bytes).expect("should be able to decode encoded wrapped `GroupKey`");
let got: GroupKey<E::CS> = eng
.unwrap(&wrapped)
.expect("should be able to unwrap `GroupKey`");
assert_eq!(want.id(), got.id());
}
pub fn test_simple_wrap_device_identity_key<E: Engine>(eng: &E) {
let want = IdentityKey::new(eng);
let bytes = cbor::to_allocvec(
&eng.wrap(want.clone())
.expect("should be able to wrap `IdentityKey`"),
)
.expect("should be able to encode wrapped `IdentityKey`");
let wrapped =
cbor::from_bytes(&bytes).expect("should be able to decode encoded wrapped `IdentityKey`");
let got: IdentityKey<E::CS> = eng
.unwrap(&wrapped)
.expect("should be able to unwrap `IdentityKey`");
assert_eq!(want.id(), got.id());
}
pub fn test_simple_export_device_identity_key<E: Engine>(eng: &E) {
let want = IdentityKey::<E::CS>::new(eng)
.public()
.expect("identity key should be valid");
let bytes =
cbor::to_allocvec(&want).expect("should be able to encode an `IdentityVerifyingKey`");
let got = cbor::from_bytes(&bytes).expect("should be able to decode an `IdentityVerifyingKey`");
assert_eq!(want, got);
}
pub fn test_simple_identity_key_sign<E: Engine>(eng: &E) {
let sign_key = IdentityKey::<E::CS>::new(eng);
const MESSAGE: &[u8] = b"hello, world!";
const CONTEXT: &[u8] = b"test_simple_identity_key_sign";
let sig = sign_key
.sign(MESSAGE, CONTEXT)
.expect("should not fail to create signature");
sign_key
.public()
.expect("sender signing key should be valid")
.verify(MESSAGE, CONTEXT, &sig)
.expect("should not fail with correct signature");
sign_key
.public()
.expect("sender signing key should be valid")
.verify(MESSAGE, b"wrong context", &sig)
.expect_err("should fail with wrong context");
let wrong_sig = sign_key
.sign(b"different", b"signature")
.expect("should not fail to create signature");
sign_key
.public()
.expect("sender signing key should be valid")
.verify(MESSAGE, CONTEXT, &wrong_sig)
.expect_err("should fail with wrong signature");
}
pub fn test_simple_wrap_device_signing_key<E: Engine>(eng: &E) {
let want = DeviceSigningKey::new(eng);
let bytes = cbor::to_allocvec(
&eng.wrap(want.clone())
.expect("should be able to wrap `DeviceSigningKey`"),
)
.expect("should be able to encode wrapped `DeviceSigningKey`");
let wrapped = cbor::from_bytes(&bytes)
.expect("should be able to decode encoded wrapped `DeviceSigningKey`");
let got: DeviceSigningKey<E::CS> = eng
.unwrap(&wrapped)
.expect("should be able to unwrap `DeviceSigningKey`");
assert_eq!(want.id(), got.id());
}
pub fn test_simple_export_device_signing_key<E: Engine>(eng: &E) {
let want = DeviceSigningKey::<E::CS>::new(eng)
.public()
.expect("device signing key should be valid");
let bytes = cbor::to_allocvec(&want).expect("should be able to encode an `VerifyingKey`");
let got = cbor::from_bytes(&bytes).expect("should be able to decode an `VerifyingKey`");
assert_eq!(want, got);
}
pub fn test_simple_wrap_device_encryption_key<E: Engine>(eng: &E) {
let want = EncryptionKey::new(eng);
let bytes = cbor::to_allocvec(
&eng.wrap(want.clone())
.expect("should be able to wrap `EncryptionKey`"),
)
.expect("should be able to encode wrapped `EncryptionKey`");
let wrapped =
cbor::from_bytes(&bytes).expect("should be able to decode encoded wrapped `EncryptionKey`");
let got: EncryptionKey<E::CS> = eng
.unwrap(&wrapped)
.expect("should be able to unwrap `EncryptionKey`");
assert_eq!(want.id(), got.id());
}
pub fn test_simple_export_device_encryption_key<E: Engine>(eng: &E) {
let want = EncryptionKey::<E::CS>::new(eng)
.public()
.expect("encryption public key should be valid");
let bytes =
cbor::to_allocvec(&want).expect("should be able to encode an `EncryptionPublicKey`");
let got = cbor::from_bytes(&bytes).expect("should be able to decode an `EncryptionPublicKey`");
assert_eq!(want, got);
}
pub fn test_group_key_seal<E: Engine>(eng: &E) {
const INPUT: &[u8] = b"hello, world!";
let author_sign_pk = DeviceSigningKey::<E::CS>::new(eng)
.public()
.expect("author signing key should be valid");
let gk = GroupKey::new(eng);
let ciphertext = {
let mut dst = vec![0u8; INPUT.len() + gk.overhead()];
gk.seal(
eng,
&mut dst,
INPUT,
Context {
label: "test_group_key_seal",
parent: CmdId::default(),
author_sign_pk: &author_sign_pk,
},
)
.expect("should succeed");
dst
};
let plaintext = {
let mut dst = vec![0u8; ciphertext.len() - gk.overhead()];
gk.open(
&mut dst,
&ciphertext,
Context {
label: "test_group_key_seal",
parent: CmdId::default(),
author_sign_pk: &author_sign_pk,
},
)
.expect("should succeed");
dst
};
assert_eq!(&plaintext, INPUT);
}
pub fn test_group_key_open_wrong_key<E: Engine>(eng: &E) {
const INPUT: &[u8] = b"hello, world!";
let author_sign_pk = DeviceSigningKey::<E::CS>::new(eng)
.public()
.expect("author signing key should be valid");
let gk1 = GroupKey::new(eng);
let gk2 = GroupKey::new(eng);
let ciphertext = {
let mut dst = vec![0u8; INPUT.len() + gk1.overhead()];
gk1.seal(
eng,
&mut dst,
INPUT,
Context {
label: "some label",
parent: CmdId::default(),
author_sign_pk: &author_sign_pk,
},
)
.expect("should succeed");
dst
};
let mut dst = vec![0u8; ciphertext.len() - gk2.overhead()];
let err = gk2
.open(
&mut dst,
&ciphertext,
Context {
label: "some label",
parent: CmdId::default(),
author_sign_pk: &author_sign_pk,
},
)
.expect_err("should have failed");
assert_eq!(err, Error::Open(OpenError::Authentication));
}
pub fn test_group_key_open_wrong_context<E: Engine>(eng: &E) {
const INPUT: &[u8] = b"hello, world!";
let author_pk1 = DeviceSigningKey::<E::CS>::new(eng)
.public()
.expect("author 1 signing key should be valid");
let author_pk2 = DeviceSigningKey::<E::CS>::new(eng)
.public()
.expect("author 2 signing key should be valid");
let gk = GroupKey::new(eng);
let ciphertext = {
let mut dst = vec![0u8; INPUT.len() + gk.overhead()];
gk.seal(
eng,
&mut dst,
INPUT,
Context {
label: "some label",
parent: CmdId::default(),
author_sign_pk: &author_pk1,
},
)
.expect("should succeed");
dst
};
macro_rules! should_fail {
($msg:expr, $ctx:expr) => {
let mut dst = vec![0u8; ciphertext.len() - gk.overhead()];
let err = gk
.open(&mut dst, &ciphertext, $ctx)
.expect_err("should have failed");
assert_eq!(err, Error::Open(OpenError::Authentication), $msg);
};
}
should_fail!(
"wrong label",
Context {
label: "wrong label",
parent: CmdId::default(),
author_sign_pk: &author_pk1,
}
);
should_fail!(
"wrong `parent`",
Context {
label: "some label",
parent: [1u8; 32].into(),
author_sign_pk: &author_pk1,
}
);
should_fail!(
"wrong `author`",
Context {
label: "some label",
parent: CmdId::default(),
author_sign_pk: &author_pk2,
}
);
}
pub fn test_group_key_open_bad_ciphertext<E: Engine>(eng: &E) {
const INPUT: &[u8] = b"hello, world!";
let author_sign_pk = DeviceSigningKey::<E::CS>::new(eng)
.public()
.expect("author signing key should be valid");
let gk = GroupKey::new(eng);
let mut ciphertext = {
let mut dst = vec![0u8; INPUT.len() + gk.overhead()];
gk.seal(
eng,
&mut dst,
INPUT,
Context {
label: "some label",
parent: CmdId::default(),
author_sign_pk: &author_sign_pk,
},
)
.expect("should succeed");
dst
};
ciphertext[0] = ciphertext[0].wrapping_add(1);
let mut dst = vec![0u8; ciphertext.len() - gk.overhead()];
let err = gk
.open(
&mut dst,
&ciphertext,
Context {
label: "some label",
parent: CmdId::default(),
author_sign_pk: &author_sign_pk,
},
)
.expect_err("should have failed");
assert_eq!(err, Error::Open(OpenError::Authentication));
}
pub fn test_encrypted_group_key_encode<E: Engine>(eng: &E)
where
<<E::CS as CipherSuite>::Aead as Aead>::Overhead: Add<U64>,
Sum<<<E::CS as CipherSuite>::Aead as Aead>::Overhead, U64>: ArrayLength,
{
let enc_key = EncryptionKey::<E::CS>::new(eng);
let group = GroupId::default();
let want = GroupKey::new(eng);
let (enc, ciphertext) = enc_key
.public()
.expect("encryption public key should be valid")
.seal_group_key(eng, &want, group)
.expect("unable to encrypt `GroupKey`");
let enc = Encap::<E::CS>::from_bytes(enc.as_bytes()).expect("should be able to decode `Encap`");
let ciphertext: EncryptedGroupKey<E::CS> = cbor::from_bytes(
&cbor::to_allocvec(&ciphertext).expect("should be able to encode `EncryptedGroupKey`"),
)
.expect("should be able to decode `EncryptedGroupKey`");
let got = enc_key
.open_group_key(&enc, ciphertext, group)
.expect("unable to decrypt `GroupKey`");
assert_eq!(want.id(), got.id());
}
pub fn test_simple_sender_signing_key_sign<E: Engine>(eng: &E)
where
<<E::CS as CipherSuite>::Aead as Aead>::Overhead: Add<U64>,
Sum<<<E::CS as CipherSuite>::Aead as Aead>::Overhead, U64>: ArrayLength,
{
const RECORD: &[u8] = b"some encoded record";
const VERSION: Version = Version::new(1);
let topic = Topic::new("SomeTopic");
let sign_key = SenderSigningKey::<E::CS>::new(eng);
let sig = sign_key
.sign(VERSION, &topic, RECORD)
.expect("unable to create signature");
sign_key
.public()
.expect("sender signing key should be valid")
.verify(VERSION, &topic, RECORD, &sig)
.expect("the signature should be valid");
sign_key
.public()
.expect("sender signing key should be valid")
.verify(Version::new(VERSION.as_u32() + 1), &topic, RECORD, &sig)
.expect_err("should fail: wrong version");
sign_key
.public()
.expect("sender signing key should be valid")
.verify(VERSION, &Topic::new("WrongTopic"), RECORD, &sig)
.expect_err("should fail: wrong topic");
sign_key
.public()
.expect("sender signing key should be valid")
.verify(VERSION, &topic, b"wrong", &sig)
.expect_err("should fail: wrong record");
let wrong_sig = sign_key
.sign(
Version::new(VERSION.as_u32() + 1),
&Topic::new("AnotherTopic"),
b"encoded record",
)
.expect("should not fail to create signature");
sign_key
.public()
.expect("sender signing key should be valid")
.verify(VERSION, &topic, RECORD, &wrong_sig)
.expect_err("should fail: wrong signature");
}
pub fn test_simple_seal_topic_key<E: Engine>(eng: &E)
where
<<E::CS as CipherSuite>::Aead as Aead>::Overhead: Add<U64>,
Sum<<<E::CS as CipherSuite>::Aead as Aead>::Overhead, U64>: ArrayLength,
{
let send_sk = SenderSecretKey::<E::CS>::new(eng);
let send_pk = send_sk.public().expect("sender public key should be valid");
let recv_sk = ReceiverSecretKey::<E::CS>::new(eng);
let recv_pk = recv_sk
.public()
.expect("receiver public key should be valid");
const VERSION: Version = Version::new(1);
let topic = Topic::new("SomeTopic");
let want = TopicKey::new(eng, VERSION, &topic).expect("unable to create new `TopicKey`");
let (enc, ciphertext) = recv_pk
.seal_topic_key(eng, VERSION, &topic, &send_sk, &want)
.expect("unable to encrypt `TopicKey`");
let enc = Encap::<E::CS>::from_bytes(enc.as_bytes()).expect("should be able to decode `Encap`");
let ciphertext = EncryptedTopicKey::<E::CS>::from_bytes(ciphertext.as_bytes())
.expect("should be able to decode `EncryptedTopicKey`");
let got = recv_sk
.open_topic_key(VERSION, &topic, &send_pk, &enc, &ciphertext)
.expect("unable to decrypt `TopicKey`");
assert_eq!(want.id(), got.id());
}
pub fn test_simple_wrap_device_sender_secret_key<E: Engine>(eng: &E) {
let want = SenderSecretKey::new(eng);
let bytes = cbor::to_allocvec(
&eng.wrap(want.clone())
.expect("should be able to wrap `SenderSecretKey`"),
)
.expect("should be able to encode wrapped `SenderSecretKey`");
let wrapped = cbor::from_bytes(&bytes)
.expect("should be able to decode encoded wrapped `SenderSecretKey`");
let got: SenderSecretKey<E::CS> = eng
.unwrap(&wrapped)
.expect("should be able to unwrap `SenderSecretKey`");
assert_eq!(want.id(), got.id());
}
pub fn test_simple_wrap_device_sender_signing_key<E: Engine>(eng: &E) {
let want = SenderSigningKey::new(eng);
let bytes = cbor::to_allocvec(
&eng.wrap(want.clone())
.expect("should be able to wrap `SenderSigningKey`"),
)
.expect("should be able to encode wrapped `SenderSigningKey`");
let wrapped = cbor::from_bytes(&bytes)
.expect("should be able to decode encoded wrapped `SenderSigningKey`");
let got: SenderSigningKey<E::CS> = eng
.unwrap(&wrapped)
.expect("should be able to unwrap `SenderSigningKey`");
assert_eq!(want.id(), got.id());
}
pub fn test_simple_wrap_device_receiver_secret_key<E: Engine>(eng: &E) {
let want = ReceiverSecretKey::new(eng);
let bytes = cbor::to_allocvec(
&eng.wrap(want.clone())
.expect("should be able to wrap `ReceiverSecretKey`"),
)
.expect("should be able to encode wrapped `ReceiverSecretKey`");
let wrapped = cbor::from_bytes(&bytes)
.expect("should be able to decode encoded wrapped `ReceiverSecretKey`");
let got: ReceiverSecretKey<E::CS> = eng
.unwrap(&wrapped)
.expect("should be able to unwrap `ReceiverSecretKey`");
assert_eq!(want.id(), got.id());
}
pub fn test_topic_key_seal<E: Engine>(eng: &E) {
const INPUT: &[u8] = b"hello, world!";
let ident = Sender {
enc_key: &SenderSecretKey::<E::CS>::new(eng)
.public()
.expect("sender public encryption key should be valid"),
sign_key: &SenderSigningKey::<E::CS>::new(eng)
.public()
.expect("sender public signing key should be valid"),
};
const VERSION: Version = Version::new(1);
let topic = Topic::new("SomeTopic");
let tk = TopicKey::new(eng, VERSION, &topic).expect("unable to create new `TopicKey`");
let ciphertext = {
let mut dst = vec![0u8; INPUT.len() + tk.overhead()];
tk.seal_message(eng, &mut dst, INPUT, VERSION, &topic, &ident)
.expect("should succeed");
dst
};
let plaintext = {
let mut dst = vec![0u8; ciphertext.len() - tk.overhead()];
tk.open_message(&mut dst, &ciphertext, VERSION, &topic, &ident)
.expect("should succeed");
dst
};
assert_eq!(&plaintext, INPUT);
}
pub fn test_topic_key_open_wrong_key<E: Engine>(eng: &E) {
const INPUT: &[u8] = b"hello, world!";
let ident = Sender {
enc_key: &SenderSecretKey::<E::CS>::new(eng)
.public()
.expect("sender public encryption key should be valid"),
sign_key: &SenderSigningKey::<E::CS>::new(eng)
.public()
.expect("sender public signing key should be valid"),
};
const VERSION: Version = Version::new(1);
let topic = Topic::new("SomeTopic");
let tk1 = TopicKey::new(eng, VERSION, &topic).expect("unable to create new `TopicKey`");
let tk2 = TopicKey::new(eng, VERSION, &topic).expect("unable to create new `TopicKey`");
let ciphertext = {
let mut dst = vec![0u8; INPUT.len() + tk1.overhead()];
tk1.seal_message(eng, &mut dst, INPUT, VERSION, &topic, &ident)
.expect("should succeed");
dst
};
let mut dst = vec![0u8; ciphertext.len() - tk2.overhead()];
let err = tk2
.open_message(&mut dst, &ciphertext, VERSION, &topic, &ident)
.expect_err("should have failed");
assert_eq!(err, Error::Open(OpenError::Authentication));
}
pub fn test_topic_key_open_wrong_context<E: Engine>(eng: &E) {
const INPUT: &[u8] = b"hello, world!";
let ident = Sender {
enc_key: &SenderSecretKey::<E::CS>::new(eng)
.public()
.expect("sender public encryption key should be valid"),
sign_key: &SenderSigningKey::<E::CS>::new(eng)
.public()
.expect("sender public signing key should be valid"),
};
let wrong_ident = Sender {
enc_key: &SenderSecretKey::<E::CS>::new(eng)
.public()
.expect("sender public encryption key should be valid"),
sign_key: &SenderSigningKey::<E::CS>::new(eng)
.public()
.expect("sender public signing key should be valid"),
};
const VERSION: Version = Version::new(1);
let topic = Topic::new("SomeTopic");
let tk = TopicKey::new(eng, VERSION, &topic).expect("unable to create `TopicKey`");
let ciphertext = {
let mut dst = vec![0u8; INPUT.len() + tk.overhead()];
tk.seal_message(eng, &mut dst, INPUT, VERSION, &topic, &ident)
.expect("should succeed");
dst
};
macro_rules! should_fail {
($msg:expr, $version:expr, $topic:expr, $ident:expr) => {
let mut dst = vec![0u8; ciphertext.len() - tk.overhead()];
let err = tk
.open_message(&mut dst, &ciphertext, $version, $topic, $ident)
.expect_err("should have failed");
assert_eq!(err, Error::Open(OpenError::Authentication), $msg);
};
}
should_fail!(
"wrong version",
Version::new(VERSION.as_u32() + 1),
&topic,
&ident
);
should_fail!("wrong topic", VERSION, &Topic::new("WrongTopic"), &ident);
should_fail!("wrong ident", VERSION, &topic, &wrong_ident);
}
pub fn test_topic_key_open_bad_ciphertext<E: Engine>(eng: &E) {
const INPUT: &[u8] = b"hello, world!";
let ident = Sender {
enc_key: &SenderSecretKey::<E::CS>::new(eng)
.public()
.expect("sender public encryption key should be valid"),
sign_key: &SenderSigningKey::<E::CS>::new(eng)
.public()
.expect("sender public signing key should be valid"),
};
const VERSION: Version = Version::new(1);
let topic = Topic::new("SomeTopic");
let tk = TopicKey::new(eng, VERSION, &topic).expect("unable to create `TopicKey`");
let mut ciphertext = {
let mut dst = vec![0u8; INPUT.len() + tk.overhead()];
tk.seal_message(eng, &mut dst, INPUT, VERSION, &topic, &ident)
.expect("should succeed");
dst
};
ciphertext[0] = ciphertext[0].wrapping_add(1);
let mut dst = vec![0u8; ciphertext.len() - tk.overhead()];
let err = tk
.open_message(&mut dst, &ciphertext, VERSION, &topic, &ident)
.expect_err("should have failed");
assert_eq!(err, Error::Open(OpenError::Authentication));
}
fn assert_same_afc_keys<CS: CipherSuite>(seal: &mut afc::SealKey<CS>, open: &afc::OpenKey<CS>) {
const GOLDEN: &str = "hello, world!";
let ad: afc::AuthData = afc::AuthData {
version: 1,
label_id: LabelId::random(Rng),
};
let (ciphertext, seq) = {
let mut dst = vec![0u8; GOLDEN.len() + afc::SealKey::<CS>::OVERHEAD];
let seq = seal
.seal(&mut dst, GOLDEN.as_bytes(), &ad)
.expect("should be able to encrypt plaintext");
(dst, seq)
};
let mut plaintext = vec![0u8; ciphertext.len() - afc::OpenKey::<CS>::OVERHEAD];
open.open(&mut plaintext, &ciphertext, &ad, seq)
.expect("decryption failed; keys differ");
assert_eq!(
GOLDEN.as_bytes(),
&plaintext,
"`afc::OpenKey` produced incorrect plaintext"
);
}
fn assert_different_afc_keys<E: Engine>(
eng: &E,
seal: Option<afc::SealKey<E::CS>>,
open: &afc::OpenKey<E::CS>,
) {
const GOLDEN: &str = "hello, world!";
let ad: afc::AuthData = afc::AuthData {
version: 1,
label_id: LabelId::random(Rng),
};
let (ciphertext, seq) = {
let mut dst = vec![0u8; GOLDEN.len() + afc::SealKey::<E::CS>::OVERHEAD];
let seq = seal
.unwrap_or_else(|| {
afc::SealKey::from_raw(&Random::random(eng), afc::Seq::ZERO)
.expect("should be able to generate random `afc::SealKey`")
})
.seal(&mut dst, GOLDEN.as_bytes(), &ad)
.expect("should be able to encrypt plaintext");
(dst, seq)
};
let mut plaintext = vec![0u8; ciphertext.len() - afc::OpenKey::<E::CS>::OVERHEAD];
let err = open
.open(&mut plaintext, &ciphertext, &ad, seq)
.expect_err("should not be able to decrypt ciphertext with mismatched keys");
assert_eq!(
err,
afc::OpenError::Authentication,
"should have received `Authentication` error"
);
}
pub fn test_afc_same_seal_key_open_key<E: Engine>(eng: &E) {
let raw: afc::RawSealKey<E::CS> = Random::random(eng);
let mut seal = afc::SealKey::<E::CS>::from_raw(&raw, afc::Seq::ZERO)
.expect("should be able to create `afc::SealKey`");
let open = afc::OpenKey::<E::CS>::from_raw(&raw.into())
.expect("should be able to create `afc::OpenKey`");
assert_same_afc_keys(&mut seal, &open);
}
pub fn test_afc_different_seal_key_open_key<E: Engine>(eng: &E) {
let seal = afc::SealKey::from_raw(&Random::random(eng), afc::Seq::ZERO)
.expect("should be able to create `afc::SealKey`");
let open = afc::OpenKey::from_raw(&Random::random(eng))
.expect("should be able to create `afc::OpenKey`");
assert_different_afc_keys(eng, Some(seal), &open);
assert_different_afc_keys(eng, None, &open);
}
pub fn test_afc_seal_key_monotonic_seq_number<E: Engine>(eng: &E) {
let mut seal = afc::SealKey::<E::CS>::from_raw(&Random::random(eng), afc::Seq::ZERO)
.expect("should be able to create `afc::SealKey`");
const GOLDEN: &str = "hello, world!";
let ad: afc::AuthData = afc::AuthData {
version: 1,
label_id: LabelId::random(Rng),
};
let mut dst = vec![0u8; GOLDEN.len() + afc::SealKey::<E::CS>::OVERHEAD];
for idx in 0..u16::MAX {
let seq = seal
.seal(&mut dst, GOLDEN.as_bytes(), &ad)
.expect("should be able to encrypt plaintext");
assert_eq!(seq, afc::Seq::new(u64::from(idx)));
}
}
pub fn test_afc_seal_key_seq_number_exhausted<E: Engine>(eng: &E) {
let max = afc::Seq::max::<<<E::CS as CipherSuite>::Aead as Aead>::NonceSize>();
let start = afc::Seq::new(max - 1);
let mut seal = afc::SealKey::<E::CS>::from_raw(&Random::random(eng), start)
.expect("should be able to create `afc::SealKey`");
const GOLDEN: &str = "hello, world!";
let ad: afc::AuthData = afc::AuthData {
version: 1,
label_id: LabelId::random(Rng),
};
let mut dst = vec![0u8; GOLDEN.len() + afc::SealKey::<E::CS>::OVERHEAD];
let seq = seal
.seal(&mut dst, GOLDEN.as_bytes(), &ad)
.expect("should be able to encrypt plaintext");
assert_eq!(seq, afc::Seq::new(max - 1));
let err = seal
.seal(&mut dst, GOLDEN.as_bytes(), &ad)
.expect_err("sequence counter should be exhausted");
assert_eq!(err, afc::SealError::MessageLimitReached);
}
pub fn test_afc_open_key_seq_number_exhausted<E: Engine>(eng: &E) {
let raw: afc::RawSealKey<E::CS> = Random::random(eng);
let mut seal = afc::SealKey::<E::CS>::from_raw(&raw, afc::Seq::ZERO)
.expect("should be able to create `afc::SealKey`");
let open =
afc::OpenKey::from_raw(&raw.into()).expect("should be able to create `afc::OpenKey`");
assert_same_afc_keys(&mut seal, &open);
const GOLDEN: &str = "hello, world!";
let ad: afc::AuthData = afc::AuthData {
version: 1,
label_id: LabelId::random(Rng),
};
let mut ciphertext = vec![0u8; GOLDEN.len() + afc::SealKey::<E::CS>::OVERHEAD];
let mut plaintext = vec![0u8; ciphertext.len() - afc::OpenKey::<E::CS>::OVERHEAD];
seal.seal(&mut ciphertext, GOLDEN.as_bytes(), &ad)
.expect("should be able to encrypt plaintext");
let exhausted_seq = afc::Seq::new(afc::Seq::max::<
<<E::CS as CipherSuite>::Aead as Aead>::NonceSize,
>());
let err = open
.open(&mut plaintext, &ciphertext, &ad, exhausted_seq)
.expect_err("should not be able to decrypt ciphertext with exhausted seq number");
assert_eq!(
err,
afc::OpenError::MessageLimitReached,
"should have received `MessageLimitReached` error"
);
}
pub fn test_afc_open_key_wrong_seq_number<E: Engine>(eng: &E) {
let raw: afc::RawSealKey<E::CS> = Random::random(eng);
let mut seal = afc::SealKey::<E::CS>::from_raw(&raw, afc::Seq::ZERO)
.expect("should be able to create `afc::SealKey`");
let open =
afc::OpenKey::from_raw(&raw.into()).expect("should be able to create `afc::OpenKey`");
assert_same_afc_keys(&mut seal, &open);
const GOLDEN: &str = "hello, world!";
let ad: afc::AuthData = afc::AuthData {
version: 1,
label_id: LabelId::random(Rng),
};
let mut ciphertext = vec![0u8; GOLDEN.len() + afc::SealKey::<E::CS>::OVERHEAD];
let mut plaintext = vec![0u8; ciphertext.len() - afc::OpenKey::<E::CS>::OVERHEAD];
for _ in 0..100 {
let seq = seal
.seal(&mut ciphertext, GOLDEN.as_bytes(), &ad)
.expect("should be able to encrypt plaintext");
let wrong_seq = afc::Seq::new(seq.to_u64() + 1);
let err = open
.open(&mut plaintext, &ciphertext, &ad, wrong_seq)
.expect_err("should not be able to decrypt ciphertext with the wrong seq number");
assert_eq!(
err,
afc::OpenError::Authentication,
"should have received `Authentication` error"
);
}
}
pub fn test_afc_open_key_wrong_auth_data<E: Engine>(eng: &E) {
let raw: afc::RawSealKey<E::CS> = Random::random(eng);
let mut seal = afc::SealKey::<E::CS>::from_raw(&raw, afc::Seq::ZERO)
.expect("should be able to create `afc::SealKey`");
let open =
afc::OpenKey::from_raw(&raw.into()).expect("should be able to create `afc::OpenKey`");
assert_same_afc_keys(&mut seal, &open);
const GOLDEN: &str = "hello, world!";
let good_ad: afc::AuthData = afc::AuthData {
version: 1,
label_id: LabelId::random(Rng),
};
let bad_ad: afc::AuthData = afc::AuthData {
version: 3,
label_id: LabelId::random(Rng),
};
let mut ciphertext = vec![0u8; GOLDEN.len() + afc::SealKey::<E::CS>::OVERHEAD];
let seq = seal
.seal(&mut ciphertext, GOLDEN.as_bytes(), &good_ad)
.expect("should be able to encrypt plaintext");
let mut plaintext = vec![0u8; ciphertext.len() - afc::OpenKey::<E::CS>::OVERHEAD];
let err = open
.open(&mut plaintext, &ciphertext, &bad_ad, seq)
.expect_err("should not be able to decrypt ciphertext with the wrong `afc::AuthData`");
assert_eq!(
err,
afc::OpenError::Authentication,
"should have received `Authentication` error"
);
}
fn assert_same_afc_uni_key<CS: CipherSuite>(seal: afc::UniSealKey<CS>, open: afc::UniOpenKey<CS>) {
{
let seal = seal.as_raw_key();
let open = open.as_raw_key();
assert_ct_eq!(seal.to_testing_key(), open.to_testing_key());
}
let mut seal = seal.into_key().expect("should have got `afc::SealKey`");
let open = open.into_key().expect("should have got `afc::OpenKey`");
assert_same_afc_keys(&mut seal, &open);
}
fn assert_different_afc_uni_key<E: Engine>(
eng: &E,
seal: afc::UniSealKey<E::CS>,
open: afc::UniOpenKey<E::CS>,
) {
{
let seal = seal.as_raw_key();
let open = open.as_raw_key();
assert_ct_ne!(seal.to_testing_key(), open.to_testing_key());
}
let seal = seal.into_key().expect("should have got `afc::SealKey`");
let open = open.into_key().expect("should have got `afc::OpenKey`");
assert_different_afc_keys(eng, Some(seal), &open);
assert_different_afc_keys(eng, None, &open);
}
pub fn test_afc_derive_uni_key<E: Engine>(eng: &E) {
let sk1 = EncryptionKey::<E::CS>::new(eng);
let sk2 = EncryptionKey::<E::CS>::new(eng);
let label_id = LabelId::random(eng);
let ch1 = afc::UniChannel {
parent_cmd_id: CmdId::random(eng),
our_sk: &sk1,
their_pk: &sk2
.public()
.expect("receiver public encryption key should be valid"),
seal_id: IdentityKey::<E::CS>::new(eng)
.id()
.expect("seal id should be valid"),
open_id: IdentityKey::<E::CS>::new(eng)
.id()
.expect("open id should be valid"),
label_id,
};
let ch2 = afc::UniChannel {
parent_cmd_id: ch1.parent_cmd_id,
our_sk: &sk2,
their_pk: &sk1
.public()
.expect("receiver public encryption key should be valid"),
seal_id: ch1.seal_id,
open_id: ch1.open_id,
label_id,
};
assert_eq!(ch1.info(), ch2.info());
let afc::UniSecrets { author, peer } =
afc::UniSecrets::new(eng, &ch1).expect("unable to create `afc::UniSecrets`");
let ck1 = afc::UniSealKey::from_author_secret(&ch1, author)
.expect("unable to decrypt author `afc::UniSealKey`");
let ck2 = afc::UniOpenKey::from_peer_encap(&ch2, peer)
.expect("unable to decrypt peer `afc::UniOpenKey`");
assert_same_afc_uni_key(ck1, ck2);
}
pub fn test_afc_derive_uni_key_different_labels<E: Engine>(eng: &E) {
let sk1 = EncryptionKey::<E::CS>::new(eng);
let sk2 = EncryptionKey::<E::CS>::new(eng);
let ch1 = afc::UniChannel {
parent_cmd_id: CmdId::random(eng),
our_sk: &sk1,
their_pk: &sk2
.public()
.expect("receiver public encryption key should be valid"),
seal_id: IdentityKey::<E::CS>::new(eng)
.id()
.expect("seal id should be valid"),
open_id: IdentityKey::<E::CS>::new(eng)
.id()
.expect("open id should be valid"),
label_id: LabelId::random(eng),
};
let ch2 = afc::UniChannel {
parent_cmd_id: ch1.parent_cmd_id,
our_sk: &sk2,
their_pk: &sk1
.public()
.expect("receiver public encryption key should be valid"),
seal_id: ch1.seal_id,
open_id: ch1.open_id,
label_id: LabelId::random(eng),
};
assert_ne!(ch1.info(), ch2.info());
let afc::UniSecrets { author, peer } =
afc::UniSecrets::new(eng, &ch1).expect("unable to create `afc::UniSecrets`");
let ck1 = afc::UniSealKey::from_author_secret(&ch1, author)
.expect("unable to decrypt author `afc::UniSealKey`");
let ck2 = afc::UniOpenKey::from_peer_encap(&ch2, peer)
.expect("unable to decrypt peer `afc::UniOpenKey`");
assert_different_afc_uni_key(eng, ck1, ck2);
}
pub fn test_afc_derive_uni_key_different_device_ids<E: Engine>(eng: &E) {
let label_id = LabelId::random(eng);
let sk1 = EncryptionKey::<E::CS>::new(eng);
let sk2 = EncryptionKey::<E::CS>::new(eng);
let ch1 = afc::UniChannel {
parent_cmd_id: CmdId::random(eng),
our_sk: &sk1,
their_pk: &sk2
.public()
.expect("receiver public encryption key should be valid"),
seal_id: IdentityKey::<E::CS>::new(eng)
.id()
.expect("seal id should be valid"),
open_id: IdentityKey::<E::CS>::new(eng)
.id()
.expect("open id should be valid"),
label_id,
};
let ch2 = afc::UniChannel {
parent_cmd_id: ch1.parent_cmd_id,
our_sk: &sk2,
their_pk: &sk1
.public()
.expect("receiver public encryption key should be valid"),
seal_id: ch1.seal_id,
open_id: DeviceId::random(eng),
label_id,
};
assert_ne!(ch1.info(), ch2.info());
let afc::UniSecrets { author, peer } =
afc::UniSecrets::new(eng, &ch1).expect("unable to create `afc::UniSecrets`");
let ck1 = afc::UniSealKey::from_author_secret(&ch1, author)
.expect("unable to decrypt author `afc::UniSealKey`");
let ck2 = afc::UniOpenKey::from_peer_encap(&ch2, peer)
.expect("unable to decrypt peer `afc::UniOpenKey`");
assert_different_afc_uni_key(eng, ck1, ck2);
}
pub fn test_afc_derive_uni_key_different_cmd_ids<E: Engine>(eng: &E) {
let label_id = LabelId::random(eng);
let sk1 = EncryptionKey::<E::CS>::new(eng);
let sk2 = EncryptionKey::<E::CS>::new(eng);
let ch1 = afc::UniChannel {
parent_cmd_id: CmdId::random(eng),
our_sk: &sk1,
their_pk: &sk2
.public()
.expect("receiver public encryption key should be valid"),
seal_id: IdentityKey::<E::CS>::new(eng)
.id()
.expect("seal id should be valid"),
open_id: IdentityKey::<E::CS>::new(eng)
.id()
.expect("open id should be valid"),
label_id,
};
let ch2 = afc::UniChannel {
parent_cmd_id: CmdId::random(eng),
our_sk: &sk2,
their_pk: &sk1
.public()
.expect("receiver public encryption key should be valid"),
seal_id: ch1.seal_id,
open_id: ch1.open_id,
label_id,
};
assert_ne!(ch1.info(), ch2.info());
let afc::UniSecrets { author, peer } =
afc::UniSecrets::new(eng, &ch1).expect("unable to create `afc::UniSecrets`");
let ck1 = afc::UniSealKey::from_author_secret(&ch1, author)
.expect("unable to decrypt author `afc::UniSealKey`");
let ck2 = afc::UniOpenKey::from_peer_encap(&ch2, peer)
.expect("unable to decrypt peer `afc::UniOpenKey`");
assert_different_afc_uni_key(eng, ck1, ck2);
}
pub fn test_afc_derive_uni_key_different_keys<E: Engine>(eng: &E) {
let label_id = LabelId::random(eng);
let sk1 = EncryptionKey::<E::CS>::new(eng);
let sk2 = EncryptionKey::<E::CS>::new(eng);
let ch1 = afc::UniChannel {
parent_cmd_id: CmdId::random(eng),
our_sk: &sk1,
their_pk: &sk2
.public()
.expect("receiver public encryption key should be valid"),
seal_id: IdentityKey::<E::CS>::new(eng)
.id()
.expect("seal id should be valid"),
open_id: IdentityKey::<E::CS>::new(eng)
.id()
.expect("open id should be valid"),
label_id,
};
let ch2 = afc::UniChannel {
parent_cmd_id: ch1.parent_cmd_id,
our_sk: &sk2,
their_pk: &EncryptionKey::<E::CS>::new(eng)
.public()
.expect("receiver public encryption key should be valid"),
seal_id: ch1.seal_id,
open_id: ch1.open_id,
label_id,
};
let afc::UniSecrets { author, peer } =
afc::UniSecrets::new(eng, &ch1).expect("unable to create `afc::UniSecrets`");
let ck1 = afc::UniSealKey::from_author_secret(&ch1, author)
.expect("unable to decrypt author `afc::UniSealKey`");
let ck2 = afc::UniOpenKey::from_peer_encap(&ch2, peer)
.expect("unable to decrypt peer `afc::UniOpenKey`");
assert_different_afc_uni_key(eng, ck1, ck2);
}
pub fn test_afc_derive_uni_seal_key_same_device_id<E: Engine>(eng: &E) {
let label_id = LabelId::random(eng);
let sk1 = EncryptionKey::<E::CS>::new(eng);
let sk2 = EncryptionKey::<E::CS>::new(eng);
let mut ch1 = afc::UniChannel {
parent_cmd_id: CmdId::random(eng),
our_sk: &sk1,
their_pk: &sk2
.public()
.expect("receiver public encryption key should be valid"),
seal_id: IdentityKey::<E::CS>::new(eng)
.id()
.expect("seal id should be valid"),
open_id: IdentityKey::<E::CS>::new(eng)
.id()
.expect("open id should be valid"),
label_id,
};
let mut ch2 = afc::UniChannel {
parent_cmd_id: ch1.parent_cmd_id,
our_sk: &sk2,
their_pk: &EncryptionKey::<E::CS>::new(eng)
.public()
.expect("receiver public encryption key should be valid"),
seal_id: ch1.seal_id,
open_id: ch1.open_id,
label_id,
};
assert_eq!(ch1.info(), ch2.info());
let afc::UniSecrets { peer, .. } = {
let prev = ch1.seal_id;
ch1.seal_id = ch1.open_id;
let err = afc::UniSecrets::new(eng, &ch1)
.err()
.expect("should not be able to create `afc::UniSecrets`");
assert_eq!(err, Error::same_device_id());
ch1.seal_id = prev;
afc::UniSecrets::new(eng, &ch1).expect("unable to create `afc::UniSecrets`")
};
ch2.seal_id = ch2.open_id;
let err = afc::UniSealKey::from_peer_encap(&ch2, peer)
.err()
.expect("should not be able to decrypt `afc::UniSealKey`");
assert_eq!(err, Error::same_device_id());
}
pub fn test_afc_derive_uni_open_key_same_device_id<E: Engine>(eng: &E) {
let label_id = LabelId::random(eng);
let sk1 = EncryptionKey::<E::CS>::new(eng);
let sk2 = EncryptionKey::<E::CS>::new(eng);
let mut ch1 = afc::UniChannel {
parent_cmd_id: CmdId::random(eng),
our_sk: &sk1,
their_pk: &sk2
.public()
.expect("receiver public encryption key should be valid"),
seal_id: IdentityKey::<E::CS>::new(eng)
.id()
.expect("seal id should be valid"),
open_id: IdentityKey::<E::CS>::new(eng)
.id()
.expect("open id should be valid"),
label_id,
};
let mut ch2 = afc::UniChannel {
parent_cmd_id: ch1.parent_cmd_id,
our_sk: &sk2,
their_pk: &EncryptionKey::<E::CS>::new(eng)
.public()
.expect("receiver public encryption key should be valid"),
seal_id: ch1.seal_id,
open_id: ch1.open_id,
label_id,
};
assert_eq!(ch1.info(), ch2.info());
let afc::UniSecrets { peer, .. } = {
let prev = ch1.seal_id;
ch1.seal_id = ch1.open_id;
let err = afc::UniSecrets::new(eng, &ch1)
.err()
.expect("should not be able to create `afc::UniSecrets`");
assert_eq!(err, Error::same_device_id());
ch1.seal_id = prev;
afc::UniSecrets::new(eng, &ch1).expect("unable to create `afc::UniSecrets`")
};
ch2.seal_id = ch2.open_id;
let err = afc::UniOpenKey::from_peer_encap(&ch2, peer)
.err()
.expect("should not be able to decrypt `afc::UniOpenKey`");
assert_eq!(err, Error::same_device_id());
}
pub fn test_afc_wrap_uni_author_secret<E: Engine>(eng: &E) {
let sk1 = EncryptionKey::new(eng);
let sk2 = EncryptionKey::new(eng);
let ch = afc::UniChannel {
parent_cmd_id: CmdId::random(eng),
our_sk: &sk1,
their_pk: &sk2
.public()
.expect("receiver public encryption key should be valid"),
seal_id: IdentityKey::<E::CS>::new(eng)
.id()
.expect("seal id should be valid"),
open_id: IdentityKey::<E::CS>::new(eng)
.id()
.expect("open id should be valid"),
label_id: LabelId::random(eng),
};
let afc::UniSecrets { author: want, .. } =
afc::UniSecrets::new(eng, &ch).expect("unable to create `afc::UniSecrets`");
let bytes = cbor::to_allocvec(
&eng.wrap(want.clone())
.expect("should be able to wrap `afc::UniAuthorSecret`"),
)
.expect("should be able to encode wrapped `afc::UniAuthorSecret`");
let wrapped = cbor::from_bytes(&bytes)
.expect("should be able to decode encoded wrapped `afc::UniAuthorSecret`");
let got: afc::UniAuthorSecret<E::CS> = eng
.unwrap(&wrapped)
.expect("should be able to unwrap `afc::UniAuthorSecret`");
assert_ct_eq!(want, got);
}
pub fn test_tls_psk_different_suites<E: Engine>(eng: &E) {
let seed = tls::PskSeed::<E::CS>::new(eng, &GroupId::default());
let mut ids = BTreeSet::new();
let mut secrets = BTreeSet::new();
let psks = seed
.generate_psks(
b"context",
GroupId::default(),
PolicyId::default(),
tls::CipherSuiteId::all().iter().copied(),
)
.collect::<Result<Vec<_>, _>>()
.unwrap();
for psk in &psks {
let ident = psk.identity();
if !ids.insert(ident.as_bytes()) {
let cs = ident.cipher_suite();
panic!("duplicate PSK identity for {cs}: {ident}");
}
if !secrets.insert(psk.raw_secret_bytes().to_vec()) {
panic!(
"duplicate PSK secret for {}: {:?}",
psk.identity().cipher_suite(),
psk.raw_secret_bytes(),
);
}
}
}
pub fn test_tls_psk_different_contexts<E: Engine>(eng: &E) {
let seed = tls::PskSeed::<E::CS>::new(eng, &GroupId::default());
let psks1 = seed
.clone()
.generate_psks(
b"CONTEXT",
GroupId::default(),
PolicyId::default(),
tls::CipherSuiteId::all().iter().copied(),
)
.collect::<Result<Vec<_>, _>>()
.unwrap();
let psks2 = seed
.generate_psks(
b"different context",
GroupId::default(),
PolicyId::default(),
tls::CipherSuiteId::all().iter().copied(),
)
.collect::<Result<Vec<_>, _>>()
.unwrap();
assert_eq!(psks1.len(), psks2.len());
for (i, (lhs, rhs)) in psks1.into_iter().zip(psks2).enumerate() {
assert_ct_ne!(lhs, rhs, "#{i}");
}
}
pub fn test_tls_psk_different_groups<E: Engine>(eng: &E) {
let seed = tls::PskSeed::<E::CS>::new(eng, &GroupId::default());
let psks1 = seed
.clone()
.generate_psks(
b"context",
GroupId::random(eng),
PolicyId::default(),
tls::CipherSuiteId::all().iter().copied(),
)
.collect::<Result<Vec<_>, _>>()
.unwrap();
let psks2 = seed
.generate_psks(
b"context",
GroupId::random(eng),
PolicyId::default(),
tls::CipherSuiteId::all().iter().copied(),
)
.collect::<Result<Vec<_>, _>>()
.unwrap();
assert_eq!(psks1.len(), psks2.len());
for (i, (lhs, rhs)) in psks1.into_iter().zip(psks2).enumerate() {
assert_ct_ne!(lhs, rhs, "#{i}");
}
}
pub fn test_tls_psk_different_policy_ids<E: Engine>(eng: &E) {
let seed = tls::PskSeed::<E::CS>::new(eng, &GroupId::default());
let psks1 = seed
.clone()
.generate_psks(
b"context",
GroupId::default(),
PolicyId::random(eng),
tls::CipherSuiteId::all().iter().copied(),
)
.collect::<Result<Vec<_>, _>>()
.unwrap();
let psks2 = seed
.generate_psks(
b"context",
GroupId::default(),
PolicyId::random(eng),
tls::CipherSuiteId::all().iter().copied(),
)
.collect::<Result<Vec<_>, _>>()
.unwrap();
assert_eq!(psks1.len(), psks2.len());
for (i, (lhs, rhs)) in psks1.into_iter().zip(psks2).enumerate() {
assert_ct_ne!(lhs, rhs, "#{i}");
}
}
pub fn test_tls_psk_seed_simple_wrap<E: Engine>(eng: &E) {
let want = tls::PskSeed::new(eng, &GroupId::default());
let bytes = cbor::to_allocvec(
&eng.wrap(want.clone())
.expect("should be able to wrap `tls::PskSeed`"),
)
.expect("should be able to encode wrapped `tls::PskSeed`");
let wrapped =
cbor::from_bytes(&bytes).expect("should be able to decode encoded wrapped `tls::PskSeed`");
let got: tls::PskSeed<E::CS> = eng
.unwrap(&wrapped)
.expect("should be able to unwrap `tls::PskSeed`");
assert_eq!(want.id(), got.id());
}
pub fn test_tls_psk_seed_seal_open<E: Engine>(eng: &E) {
let sk1 = EncryptionKey::<E::CS>::new(eng);
let pk1 = sk1.public().expect("`sk1` public half should be valid");
let sk2 = EncryptionKey::<E::CS>::new(eng);
let pk2 = sk2.public().expect("`sk2` public half should be valid");
let group = GroupId::default();
let seed = tls::PskSeed::new(eng, &GroupId::default());
let (enc, ct) = {
let (enc, ct) = sk1
.seal_psk_seed(eng, &seed, &pk2, &group)
.expect("unable to encrypt `PskSeed`");
let enc_buf = cbor::to_allocvec(&enc).expect("unable to encode `PskSeedEnc`");
let ct_buf = cbor::to_allocvec(&ct).expect("unable to encode `PskSeedCt`");
let enc = cbor::from_bytes(&enc_buf).expect("unable to decode `PskSeedEnc`");
let ct = cbor::from_bytes(&ct_buf).expect("unable to decode `PskSeedCt`");
(enc, ct)
};
let got = sk2
.open_psk_seed(&enc, ct, &pk1, &group)
.expect("unable to decrypt `PskSeed`");
assert_ct_eq!(got, seed);
}
pub fn test_tls_psk_seed_open_wrong_peer_pk<E: Engine>(eng: &E) {
let sk1 = EncryptionKey::<E::CS>::new(eng);
let sk2 = EncryptionKey::<E::CS>::new(eng);
let pk2 = sk2.public().expect("`sk2` public half should be valid");
let sk3 = EncryptionKey::<E::CS>::new(eng);
let pk3 = sk3.public().expect("`sk3` public half should be valid");
assert_ne!(pk2, pk3);
let group = GroupId::default();
let seed = tls::PskSeed::new(eng, &GroupId::default());
let (enc, ct) = sk1
.seal_psk_seed(eng, &seed, &pk2, &group)
.expect("unable to encrypt `PskSeed`");
let err = sk2
.open_psk_seed(&enc, ct, &pk3, &group)
.expect_err("`PskSeed` decryption should fail");
assert_eq!(err, Error::Hpke(HpkeError::Open(OpenError::Authentication)));
}
pub fn test_tls_psk_seed_open_wrong_sk<E: Engine>(eng: &E) {
let sk1 = EncryptionKey::<E::CS>::new(eng);
let pk1 = sk1.public().expect("`pk1` public half should be valid");
let sk2 = EncryptionKey::<E::CS>::new(eng);
let pk2 = sk2.public().expect("`sk2` public half should be valid");
let sk3 = EncryptionKey::<E::CS>::new(eng);
assert_ct_ne!(sk2.id().unwrap(), sk3.id().unwrap());
let group = GroupId::default();
let seed = tls::PskSeed::new(eng, &GroupId::default());
let (enc, ct) = sk1
.seal_psk_seed(eng, &seed, &pk2, &group)
.expect("unable to encrypt `PskSeed`");
let err = sk3
.open_psk_seed(&enc, ct, &pk1, &group)
.expect_err("`PskSeed` decryption should fail");
assert_eq!(err, Error::Hpke(HpkeError::Open(OpenError::Authentication)));
}
pub fn test_tls_psk_seed_open_wrong_group<E: Engine>(eng: &E) {
let sk1 = EncryptionKey::<E::CS>::new(eng);
let pk1 = sk1.public().expect("`pk1` public half should be valid");
let sk2 = EncryptionKey::<E::CS>::new(eng);
let pk2 = sk2.public().expect("`sk2` public half should be valid");
let group1 = GroupId::random(eng);
let group2 = GroupId::random(eng);
assert_ne!(group1, group2);
let seed = tls::PskSeed::new(eng, &GroupId::default());
let (enc, ct) = sk1
.seal_psk_seed(eng, &seed, &pk2, &group1)
.expect("unable to encrypt `PskSeed`");
let err = sk2
.open_psk_seed(&enc, ct, &pk1, &group2)
.expect_err("`PskSeed` decryption should fail");
assert_eq!(err, Error::Hpke(HpkeError::Open(OpenError::Authentication)));
}
pub fn test_tls_psk_seed_open_wrong_ciphertext<E: Engine>(eng: &E) {
let sk1 = EncryptionKey::<E::CS>::new(eng);
let pk1 = sk1.public().expect("`pk1` public half should be valid");
let sk2 = EncryptionKey::<E::CS>::new(eng);
let pk2 = sk2.public().expect("`sk2` public half should be valid");
let group = GroupId::default();
let seed = tls::PskSeed::new(eng, &GroupId::default());
let (enc, mut ct) = sk1
.seal_psk_seed(eng, &seed, &pk2, &group)
.expect("unable to encrypt `PskSeed`");
ct.ciphertext[0] = ct.ciphertext[0].wrapping_add(1);
let err = sk2
.open_psk_seed(&enc, ct, &pk1, &group)
.expect_err("`PskSeed` decryption should fail");
assert_eq!(err, Error::Hpke(HpkeError::Open(OpenError::Authentication)));
}
pub fn test_tls_psk_seed_open_wrong_tag<E: Engine>(eng: &E) {
let sk1 = EncryptionKey::<E::CS>::new(eng);
let pk1 = sk1.public().expect("`pk1` public half should be valid");
let sk2 = EncryptionKey::<E::CS>::new(eng);
let pk2 = sk2.public().expect("`sk2` public half should be valid");
let group = GroupId::default();
let seed = tls::PskSeed::new(eng, &GroupId::default());
let (enc, mut ct) = sk1
.seal_psk_seed(eng, &seed, &pk2, &group)
.expect("unable to encrypt `PskSeed`");
ct.tag[0] = ct.tag[0].wrapping_add(1);
let err = sk2
.open_psk_seed(&enc, ct, &pk1, &group)
.expect_err("`PskSeed` decryption should fail");
assert_eq!(err, Error::Hpke(HpkeError::Open(OpenError::Authentication)));
}