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

Add MLSMessage framework #262

Merged
merged 44 commits into from
Jul 25, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
f4c6425
Add MLSMessage framework
bifurcation Apr 20, 2022
fe8ff94
Fix build errors
bifurcation Apr 28, 2022
0d1e1ac
Revert refactor of confirmation tag computation
bifurcation Apr 28, 2022
b3f6876
clang-tidy
bifurcation Apr 28, 2022
f993b7c
CI errors
bifurcation Apr 28, 2022
13b177c
CI errors
bifurcation Apr 28, 2022
0b7f211
Apply suggestions from code review
bifurcation Apr 29, 2022
4d87cca
Respond to @bifurcation review comments
bifurcation Apr 29, 2022
7f34c67
Update the interop harness
bifurcation Apr 29, 2022
e1c5080
CI errors
bifurcation Apr 29, 2022
e57636c
clang-format
bifurcation Apr 29, 2022
641b75a
Respond to comments from @suhasHere
bifurcation Apr 29, 2022
d07e024
CI errors
bifurcation Jun 10, 2022
3f63909
Noop commit to trigger CI
bifurcation Jul 22, 2022
9cbc05a
Fix some clang-tidy errors
bifurcation Jul 22, 2022
2d2c438
More clang-tidy errors
bifurcation Jul 22, 2022
c08ba67
clang-format
bifurcation Jul 22, 2022
19521e8
Ignore cast formatting errors, too many false positives
bifurcation Jul 22, 2022
db14849
Revert "More clang-tidy errors"
bifurcation Jul 22, 2022
d6c928b
Revert "Fix some clang-tidy errors"
bifurcation Jul 22, 2022
8575c7a
Cleanup from reverts
bifurcation Jul 22, 2022
a3d4978
Add missing comma in .clang-tidy
bifurcation Jul 22, 2022
5ab3954
Adjust NOLINT
bifurcation Jul 22, 2022
843fc65
Update clang-format-action to latest
bifurcation Jul 22, 2022
2a03c56
Format the interop harness
bifurcation Jul 22, 2022
f32dc00
Apply clang-format-14
bifurcation Jul 22, 2022
9318f64
Suppress some clang-tidy warnings
bifurcation Jul 22, 2022
db1394a
More clang-tidy
bifurcation Jul 22, 2022
b9a88cb
More clang-tidy
bifurcation Jul 22, 2022
241b250
clang-format
bifurcation Jul 22, 2022
da161e5
Merge branch 'update-format' into mlsmessage
bifurcation Jul 22, 2022
fb0c1fd
Enable ASan on Windows
bifurcation Jul 22, 2022
807894f
Enable stricter compilation on Windows
bifurcation Jul 22, 2022
164bc6e
Dial back MSVC errors when they stop making sense
bifurcation Jul 22, 2022
44fa481
Revert some stuff
bifurcation Jul 22, 2022
3e378a1
Don't have global objects that use the heap
bifurcation Jul 23, 2022
89927ce
Attempt a different bytes import constructor
bifurcation Jul 24, 2022
dbf1f19
Actually use the new ctor
bifurcation Jul 24, 2022
463d98e
Properly declare sanitization with MSVC
bifurcation Jul 24, 2022
272d188
Don't use static const closures with std::visit
bifurcation Jul 24, 2022
f11255a
Fix compile errors
bifurcation Jul 24, 2022
df45c30
More static const closures
bifurcation Jul 24, 2022
12ded1c
clang-format
bifurcation Jul 24, 2022
4548316
Merge branch 'msvc' into mlsmessage
bifurcation Jul 24, 2022
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
29 changes: 13 additions & 16 deletions include/mls/key_schedule.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ struct SecretTree
size_t secret_size;
};

using ReuseGuard = std::array<uint8_t, 4>;

struct GroupKeySource
{
enum struct RatchetType
Expand All @@ -64,17 +66,13 @@ struct GroupKeySource
LeafCount group_size,
bytes encryption_secret);

std::tuple<uint32_t, KeyAndNonce> next(RatchetType type, LeafIndex sender);
KeyAndNonce get(RatchetType type, LeafIndex sender, uint32_t generation);
void erase(RatchetType type, LeafIndex sender, uint32_t generation);

MLSCiphertext encrypt(const TreeKEMPublicKey& tree,
LeafIndex index,
const bytes& sender_data_secret,
const MLSPlaintext& pt);
MLSPlaintext decrypt(const TreeKEMPublicKey& tree,
const bytes& sender_data_secret,
const MLSCiphertext& ct);
std::tuple<uint32_t, ReuseGuard, KeyAndNonce> next(ContentType content_type,
LeafIndex sender);
KeyAndNonce get(ContentType content_type,
LeafIndex sender,
uint32_t generation,
ReuseGuard reuse_guard);
void erase(ContentType type, LeafIndex sender, uint32_t generation);

private:
CipherSuite suite;
Expand All @@ -84,6 +82,7 @@ struct GroupKeySource
std::map<Key, HashRatchet> chains;

HashRatchet& chain(RatchetType type, LeafIndex sender);
HashRatchet& chain(ContentType type, LeafIndex sender);
bifurcation marked this conversation as resolved.
Show resolved Hide resolved

static const std::array<RatchetType, 2> all_ratchet_types;
};
Expand Down Expand Up @@ -144,8 +143,6 @@ struct KeyScheduleEpoch
const bytes& context) const;

GroupKeySource encryption_keys(LeafCount size) const;
bytes membership_tag(const GroupContext& context,
const MLSPlaintext& pt) const;
bytes confirmation_tag(const bytes& confirmed_transcript_hash) const;
bytes do_export(const std::string& label,
const bytes& context,
Expand Down Expand Up @@ -178,10 +175,10 @@ struct TranscriptHash
bytes confirmed_in,
const bytes& confirmation_tag);

void update(const MLSPlaintext& pt);
void update_confirmed(const MLSPlaintext& pt);
void update(const MLSMessageContentAuth& content_auth);
void update_confirmed(const MLSMessageContentAuth& content_auth);
void update_interim(const bytes& confirmation_tag);
void update_interim(const MLSPlaintext& pt);
void update_interim(const MLSMessageContentAuth& content_auth);
};

bool
Expand Down
219 changes: 149 additions & 70 deletions include/mls/messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ struct MessageRange
uint32_t sender;
uint32_t first_generation;
uint32_t last_generation;
TLS_SERIALIZABLE(sender, first_generation, last_generation);
TLS_SERIALIZABLE(sender, first_generation, last_generation)
};

struct AppAck
Expand All @@ -287,7 +287,7 @@ struct AppAck
struct GroupContextExtensions
{
ExtensionList group_context_extensions;
TLS_SERIALIZABLE(group_context_extensions);
TLS_SERIALIZABLE(group_context_extensions)
};

struct ProposalType;
Expand Down Expand Up @@ -333,7 +333,7 @@ struct ProposalType
{}

Proposal::Type val;
TLS_SERIALIZABLE(val);
TLS_SERIALIZABLE(val)
};

enum struct ProposalOrRefType : uint8_t
Expand Down Expand Up @@ -397,6 +397,9 @@ enum struct WireFormat : uint8_t
reserved = 0,
mls_plaintext = 1,
mls_ciphertext = 2,
mls_welcome = 3,
mls_group_info = 4,
mls_key_package = 5,
bifurcation marked this conversation as resolved.
Show resolved Hide resolved
};

enum struct ContentType : uint8_t
Expand Down Expand Up @@ -436,101 +439,171 @@ struct Sender
TLS_TRAITS(tls::variant<SenderType>)
};

struct MLSPlaintext
///
/// MLSMessage and friends
///
struct GroupKeySource; // XXX
bifurcation marked this conversation as resolved.
Show resolved Hide resolved

struct MLSMessageContent
{
WireFormat wire_format;
bytes group_id;
epoch_t epoch;
Sender sender;
bytes authenticated_data;
var::variant<ApplicationData, Proposal, Commit> content;

ContentType content_type() const;

TLS_SERIALIZABLE(group_id, epoch, sender, authenticated_data, content)
TLS_TRAITS(tls::pass,
tls::pass,
tls::pass,
tls::pass,
tls::variant<ContentType>)
};

struct MLSMessageAuth
{
ContentType content_type = ContentType::invalid;
bytes signature;
std::optional<bytes> confirmation_tag;
std::optional<bytes> membership_tag;

// Constructor for unmarshaling directly
MLSPlaintext();

// Constructor for decrypting
MLSPlaintext(bytes group_id,
epoch_t epoch,
Sender sender,
ContentType content_type,
bytes authenticated_data,
const bytes& content);

// Constructors for encrypting
MLSPlaintext(bytes group_id,
epoch_t epoch,
Sender sender,
ApplicationData application_data);
MLSPlaintext(bytes group_id, epoch_t epoch, Sender sender, Proposal proposal);
MLSPlaintext(bytes group_id, epoch_t epoch, Sender sender, Commit commit);

ContentType content_type() const;
friend tls::ostream& operator<<(tls::ostream& str, const MLSMessageAuth& obj);
friend tls::istream& operator>>(tls::istream& str, MLSMessageAuth& obj);
friend bool operator==(const MLSMessageAuth& lhs, const MLSMessageAuth& rhs);
};

bytes to_be_signed(const GroupContext& context) const;
void sign(const CipherSuite& suite,
const GroupContext& context,
const SignaturePrivateKey& priv);
bool verify(const CipherSuite& suite,
const GroupContext& context,
const SignaturePublicKey& pub) const;
struct MLSMessageContentAuth
{
WireFormat wire_format;
MLSMessageContent content;
MLSMessageAuth auth;

bytes membership_tag_input(const GroupContext& context) const;
bool verify_membership_tag(const bytes& tag) const;
MLSMessageContentAuth() = default;

bytes marshal_content(size_t padding_size) const;
static MLSMessageContentAuth sign(WireFormat wire_format,
MLSMessageContent content,
CipherSuite suite,
bifurcation marked this conversation as resolved.
Show resolved Hide resolved
const SignaturePrivateKey& sig_priv,
const std::optional<GroupContext>& context);
bool verify(CipherSuite suite,
const SignaturePublicKey& sig_pub,
const std::optional<GroupContext>& context) const;

bytes commit_content() const;
bytes commit_auth_data() const;

TLS_SERIALIZABLE(wire_format,
group_id,
epoch,
sender,
authenticated_data,
content,
signature,
confirmation_tag,
membership_tag)
TLS_TRAITS(tls::pass,
tls::pass,
tls::pass,
tls::pass,
tls::pass,
tls::variant<ContentType>,
tls::pass,
tls::pass,
tls::pass)
void set_confirmation_tag(const bytes& confirmation_tag);
bool check_confirmation_tag(const bytes& confirmation_tag) const;

friend tls::ostream& operator<<(tls::ostream& str,
const MLSMessageContentAuth& obj);
friend tls::istream& operator>>(tls::istream& str,
MLSMessageContentAuth& obj);
friend bool operator==(const MLSMessageContentAuth& lhs,
const MLSMessageContentAuth& rhs);

TLS_SERIALIZABLE(wire_format, content, auth)
bifurcation marked this conversation as resolved.
Show resolved Hide resolved

private:
MLSMessageContentAuth(WireFormat wire_format_in,
MLSMessageContent content_in);
MLSMessageContentAuth(WireFormat wire_format_in,
MLSMessageContent content_in,
MLSMessageAuth auth_in);

bytes to_be_signed(const std::optional<GroupContext>& context) const;

friend struct MLSPlaintext;
friend struct MLSCiphertext;
};

struct MLSPlaintext
{
MLSPlaintext() = default;

epoch_t get_epoch() const { return content.epoch; }

static MLSPlaintext protect(MLSMessageContentAuth content_auth,
CipherSuite suite,
const std::optional<bytes>& membership_key,
const std::optional<GroupContext>& context);
std::optional<MLSMessageContentAuth> unprotect(
CipherSuite suite,
const std::optional<bytes>& membership_key,
const std::optional<GroupContext>& context) const;

friend tls::ostream& operator<<(tls::ostream& str, const MLSPlaintext& obj);
friend tls::istream& operator>>(tls::istream& str, MLSPlaintext& obj);

private:
MLSMessageContent content;
MLSMessageAuth auth;
std::optional<bytes> membership_tag;

MLSPlaintext(MLSMessageContentAuth content_auth);

bytes membership_mac(CipherSuite suite,
const bytes& membership_key,
const std::optional<GroupContext>& context) const;
};

// struct {
// opaque group_id<0..255>;
// uint64 epoch;
// ContentType content_type;
// opaque authenticated_data<0..2^32-1>;
// opaque encrypted_sender_data<0..255>;
// opaque ciphertext<0..2^32-1>;
// } MLSCiphertext;
struct MLSCiphertext
{
WireFormat wire_format;
MLSCiphertext() = default;

epoch_t get_epoch() const { return epoch; }

static MLSCiphertext protect(MLSMessageContentAuth content_auth,
CipherSuite suite,
const LeafIndex& index,
GroupKeySource& keys,
const bytes& sender_data_secret,
size_t padding_size);
std::optional<MLSMessageContentAuth> unprotect(
CipherSuite suite,
const TreeKEMPublicKey& tree,
GroupKeySource& keys,
const bytes& sender_data_secret) const;

TLS_SERIALIZABLE(group_id,
epoch,
content_type,
authenticated_data,
encrypted_sender_data,
ciphertext)

private:
bytes group_id;
epoch_t epoch;
ContentType content_type;
bytes authenticated_data;
bytes encrypted_sender_data;
bytes ciphertext;

TLS_SERIALIZABLE(wire_format,
group_id,
epoch,
content_type,
authenticated_data,
encrypted_sender_data,
ciphertext)
MLSCiphertext(MLSMessageContent content,
bytes encrypted_sender_data_in,
bytes ciphertext_in);
};

struct MLSMessage
{
ProtocolVersion version = ProtocolVersion::mls10;
var::variant<MLSPlaintext, MLSCiphertext, Welcome, GroupInfo, KeyPackage>
message;

epoch_t epoch() const;
WireFormat wire_format() const;

MLSMessage() = default;
MLSMessage(MLSPlaintext mls_plaintext);
MLSMessage(MLSCiphertext mls_ciphertext);
MLSMessage(Welcome welcome);
MLSMessage(GroupInfo group_info);
MLSMessage(KeyPackage key_package);

bifurcation marked this conversation as resolved.
Show resolved Hide resolved
TLS_SERIALIZABLE(version, message)
TLS_TRAITS(tls::pass, tls::variant<WireFormat>)
};

} // namespace mls
Expand Down Expand Up @@ -563,4 +636,10 @@ TLS_VARIANT_MAP(mls::SenderType, mls::KeyPackageRef, member)
TLS_VARIANT_MAP(mls::SenderType, mls::PreconfiguredKeyID, preconfigured)
TLS_VARIANT_MAP(mls::SenderType, mls::NewMemberID, new_member)

TLS_VARIANT_MAP(mls::WireFormat, mls::MLSPlaintext, mls_plaintext)
TLS_VARIANT_MAP(mls::WireFormat, mls::MLSCiphertext, mls_ciphertext)
TLS_VARIANT_MAP(mls::WireFormat, mls::Welcome, mls_welcome)
TLS_VARIANT_MAP(mls::WireFormat, mls::GroupInfo, mls_group_info)
TLS_VARIANT_MAP(mls::WireFormat, mls::KeyPackage, mls_key_package)

} // namespace tls
Loading