Skip to content
This repository has been archived by the owner on Jul 27, 2022. It is now read-only.

Commit

Permalink
Merge #1666
Browse files Browse the repository at this point in the history
1666: Problem: no MLS group creation procedure (WIP #1617) r=tomtau a=tomtau

Solution:
- added MLSPlainTest message signing + verification
- encoding/decoding code for related data types
- a small test to check signing-verify works

NOTE/WIP follow-up to #1659
still missing secret derivations, message processing etc.


Co-authored-by: Tomas Tauber <[email protected]>
  • Loading branch information
bors[bot] and tomtau authored May 27, 2020
2 parents 9bc16d1 + 2815c50 commit 26fb9ee
Show file tree
Hide file tree
Showing 6 changed files with 436 additions and 23 deletions.
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion chain-tx-enclave-next/mls/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ thiserror = "1.0"
rustls = "0.17"
x509-parser = "0.7"
sha2 = "0.8.1"

hkdf = "0.8"
ra-client = { path = "../enclave-ra/ra-client" }

[target.'cfg(target_env = "sgx")'.dependencies]
Expand Down
140 changes: 130 additions & 10 deletions chain-tx-enclave-next/mls/src/group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ use crate::keypackage::Timespec;
use crate::keypackage::{self as kp, KeyPackage, OwnedKeyPackage};
use crate::message::*;
use crate::tree::*;
use crate::utils::{encode_vec_u8_u8, read_vec_u8_u8};
use ra_client::EnclaveCertVerifier;
use rustls::internal::msgs::codec::{self, Codec, Reader};
use sha2::{Digest, Sha256};
use std::collections::BTreeSet;

Expand Down Expand Up @@ -40,16 +42,51 @@ impl GroupAux {
}
}

fn add_init(&mut self, _kp: &KeyPackage) -> MLSPlaintext {
todo!()
fn get_sender(&self) -> Sender {
Sender {
sender_type: SenderType::Member,
sender: self.tree.my_pos as u32,
}
}

fn get_signed_add(&self, kp: &KeyPackage) -> MLSPlaintext {
let sender = self.get_sender();
let add_content = MLSPlaintextCommon {
group_id: self.context.group_id.clone(),
epoch: self.context.epoch,
sender,
authenticated_data: vec![],
content: ContentType::Proposal(Proposal::Add(Add {
key_package: kp.clone(),
})),
};
let to_be_signed = MLSPlaintextTBS {
context: self.context.clone(),
content: add_content.clone(),
}
.get_encoding();
let signature = self.owned_kp.private_key.sign(&to_be_signed);
MLSPlaintext {
content: add_content,
signature,
}
}

fn get_confirmed_transcript_hash(&self, _commit: &Commit) -> Vec<u8> {
todo!()
}

fn get_signed_commit(&self, _plain: &MLSPlaintextCommon) -> MLSPlaintext {
todo!()
fn get_signed_commit(&self, plain: &MLSPlaintextCommon) -> MLSPlaintext {
let to_be_signed = MLSPlaintextTBS {
context: self.context.clone(), // TODO: current or next context?
content: plain.clone(),
}
.get_encoding();
let signature = self.owned_kp.private_key.sign(&to_be_signed);
MLSPlaintext {
content: plain.clone(),
signature,
}
}

fn get_welcome_msg(&self) -> Welcome {
Expand Down Expand Up @@ -78,14 +115,12 @@ impl GroupAux {
.generate_new_epoch_secrets(commit_secret, &updated_group_context);
let confirmation =
epoch_secrets.compute_confirmation(&updated_group_context.confirmed_transcript_hash);
let sender = Sender {
sender_type: SenderType::Member,
sender: 0, // FIXME
};
let sender = self.get_sender();
let commit_content = MLSPlaintextCommon {
group_id: self.context.group_id.clone(),
epoch: self.context.epoch,
sender,
authenticated_data: vec![],
content: ContentType::Commit {
commit,
confirmation,
Expand Down Expand Up @@ -119,7 +154,7 @@ impl GroupAux {
let (context, tree) = GroupContext::init(creator_kp.keypackage.clone())?;
let mut group = GroupAux::new(context, tree, creator_kp);
let add_proposals: Vec<MLSPlaintext> =
others.iter().map(|kp| group.add_init(kp)).collect();
others.iter().map(|kp| group.get_signed_add(kp)).collect();
let (commit, welcome) = group.init_commit(&add_proposals);
Ok((group, add_proposals, commit, welcome))
}
Expand Down Expand Up @@ -151,7 +186,7 @@ impl CipherSuite {
const TDBE_GROUP_ID: &[u8] = b"Crypto.com Chain Council Node Transaction Data Bootstrap Enclave";

/// spec: draft-ietf-mls-protocol.md#group-state
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct GroupContext {
/// 0..255 bytes -- application-defined id
pub group_id: Vec<u8>,
Expand All @@ -168,9 +203,35 @@ pub struct GroupContext {
/// the messages that led to this state.
/// 0..255
pub confirmed_transcript_hash: Vec<u8>,
/// 0..2^16-1
pub extensions: Vec<ext::ExtensionEntry>,
}

impl Codec for GroupContext {
fn encode(&self, bytes: &mut Vec<u8>) {
encode_vec_u8_u8(bytes, &self.group_id);
self.epoch.encode(bytes);
encode_vec_u8_u8(bytes, &self.tree_hash);
encode_vec_u8_u8(bytes, &self.confirmed_transcript_hash);
codec::encode_vec_u16(bytes, &self.extensions);
}

fn read(r: &mut Reader) -> Option<Self> {
let group_id = read_vec_u8_u8(r)?;
let epoch = u64::read(r)?;
let tree_hash = read_vec_u8_u8(r)?;
let confirmed_transcript_hash = read_vec_u8_u8(r)?;
let extensions = codec::read_vec_u16(r)?;
Some(Self {
group_id,
epoch,
tree_hash,
confirmed_transcript_hash,
extensions,
})
}
}

impl GroupContext {
pub fn init(creator_kp: KeyPackage) -> Result<(Self, Tree), kp::Error> {
let extensions = creator_kp.payload.extensions.clone();
Expand All @@ -187,3 +248,62 @@ impl GroupContext {
))
}
}

#[cfg(test)]
mod test {

use super::*;
use crate::credential::Credential;
use crate::extensions::{self as ext, MLSExtension};
use crate::key::PrivateKey;
use crate::keypackage::{
KeyPackage, KeyPackagePayload, OwnedKeyPackage, MLS10_128_DHKEMP256_AES128GCM_SHA256_P256,
PROTOCOL_VERSION_MLS10,
};
use rustls::internal::msgs::codec::Codec;

fn get_fake_keypackage() -> OwnedKeyPackage {
let keypair = ring::signature::EcdsaKeyPair::generate_pkcs8(
&ring::signature::ECDSA_P256_SHA256_ASN1_SIGNING,
&ring::rand::SystemRandom::new(),
)
.unwrap();
let extensions = vec![
ext::SupportedVersionsExt(vec![PROTOCOL_VERSION_MLS10]).entry(),
ext::SupportedCipherSuitesExt(vec![MLS10_128_DHKEMP256_AES128GCM_SHA256_P256]).entry(),
ext::LifeTimeExt::new(0, 100).entry(),
];

let private_key = PrivateKey::from_pkcs8(keypair.as_ref()).expect("invalid private key");
let payload = KeyPackagePayload {
version: PROTOCOL_VERSION_MLS10,
cipher_suite: MLS10_128_DHKEMP256_AES128GCM_SHA256_P256,
init_key: private_key.public_key(),
credential: Credential::X509(vec![]),
extensions,
};

// sign payload
let signature = private_key.sign(&payload.get_encoding());

OwnedKeyPackage {
keypackage: KeyPackage { payload, signature },
private_key,
}
}

#[test]
fn test_sign_verify_add() {
let creator_kp = get_fake_keypackage();
let to_be_added = get_fake_keypackage().keypackage;
let (context, tree) = GroupContext::init(creator_kp.keypackage.clone()).unwrap();
let group_aux = GroupAux::new(context, tree, creator_kp);
let plain = group_aux.get_signed_add(&to_be_added);
assert!(plain
.verify_signature(
&group_aux.context,
&group_aux.owned_kp.private_key.public_key()
)
.is_ok());
}
}
1 change: 1 addition & 0 deletions chain-tx-enclave-next/mls/src/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub struct PublicKey(Vec<u8>);

impl PublicKey {
/// Verify P-256 signature
/// FIXME: types to distinguish between signature and message payloads
pub fn verify_signature(&self, msg: &[u8], sig: &[u8]) -> Result<(), error::Unspecified> {
ECDSA_P256_SHA256_ASN1.verify(self.0.as_slice().into(), msg.into(), sig.into())
}
Expand Down
Loading

0 comments on commit 26fb9ee

Please sign in to comment.