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 all 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
12 changes: 10 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,22 @@ elseif(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
endif()

if (SANITIZERS AND (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU"))
set(SANITIZERS "-fsanitize=address -fsanitize=undefined")
if (SANITIZERS)
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
set(SANITIZERS "-fsanitize=address -fsanitize=undefined")
elseif(MSVC)
set(SANITIZERS "/fsanitize=address")
endif()

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SANITIZERS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SANITIZERS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${SANITIZERS}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${SANITIZERS}")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${SANITIZERS}")
add_definitions(-DSANITIZERS)
elseif (SANITIZERS AND MSVC)
message("Enabling sanitizers")
add_definitions("/fsanitize=address")
endif()

if(CLANG_TIDY)
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ Conventions
* Snake case for variables, functions, members (`derive_epoch_keys`)
* Private member variables start with underscore (`_`)
* In general, prefer descriptive names

14 changes: 9 additions & 5 deletions cmd/interop/src/json_details.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ struct tls_serializer
TLS_SERIALIZER(mls::HPKEPublicKey)
TLS_SERIALIZER(mls::TreeKEMPublicKey)
TLS_SERIALIZER(mls::Credential)
TLS_SERIALIZER(mls::MLSMessageContentAuth)
TLS_SERIALIZER(mls::MLSPlaintext)
TLS_SERIALIZER(mls::LeafNode)
TLS_SERIALIZER(mls::UpdatePath)
Expand Down Expand Up @@ -126,18 +127,21 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(EncryptionTestVector::SenderDataInfo,
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(EncryptionTestVector::RatchetStep,
key,
nonce,
plaintext,
ciphertext)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(EncryptionTestVector::LeafInfo,
generations,
handshake_content_auth,
application_content_auth,
handshake,
application)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(EncryptionTestVector,
cipher_suite,
tree,
encryption_secret,
sender_data_secret,
padding_size,
sender_data_info,
authenticated_data,
leaves)

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(KeyScheduleTestVector::ExternalPSKInfo,
Expand Down Expand Up @@ -177,7 +181,6 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(TranscriptTestVector,
tree_hash_before,
confirmed_transcript_hash_before,
interim_transcript_hash_before,
membership_key,
confirmation_key,
credential,
commit,
Expand Down Expand Up @@ -216,9 +219,10 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(MessagesTestVector,
external_init_proposal,
app_ack_proposal,
commit,
mls_plaintext_application,
mls_plaintext_proposal,
mls_plaintext_commit,
content_auth_app,
content_auth_proposal,
content_auth_commit,
mls_plaintext,
mls_ciphertext)

} // namespace mls_vectors
61 changes: 33 additions & 28 deletions cmd/interop/src/mls_client_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,12 @@ MLSClientImpl::load_join(uint32_t join_id)
}

// Cached group state
mls::MessageOpts
MLSClientImpl::CachedState::message_opts() const
{
return { {}, encrypt_handshake, 0 };
}

void
MLSClientImpl::CachedState::reset_pending()
{
Expand All @@ -249,25 +255,15 @@ MLSClientImpl::CachedState::reset_pending()
}

std::string
MLSClientImpl::CachedState::marshal(const mls::MLSPlaintext& pt)
MLSClientImpl::CachedState::marshal(const mls::MLSMessage& msg)
{
if (encrypt_handshake) {
auto ct = state.encrypt(pt);
return bytes_to_string(tls::marshal(ct));
}

return bytes_to_string(tls::marshal(pt));
return bytes_to_string(tls::marshal(msg));
}

mls::MLSPlaintext
mls::MLSMessage
MLSClientImpl::CachedState::unmarshal(const std::string& wire)
{
if (encrypt_handshake) {
auto ct = tls::get<mls::MLSCiphertext>(string_to_bytes(wire));
return state.decrypt(ct);
}

return tls::get<mls::MLSPlaintext>(string_to_bytes(wire));
return tls::get<mls::MLSMessage>(string_to_bytes(wire));
}

uint32_t
Expand Down Expand Up @@ -513,11 +509,12 @@ MLSClientImpl::external_join(const ExternalJoinRequest* request,

auto kp = mls::KeyPackage(suite, init_priv.public_key, leaf, {}, sig_priv);

auto encrypt = request->encrypt_handshake();
auto leaf_secret = mls::random_bytes(suite.secret_size());
auto [commit, state] = mls::State::external_join(
leaf_secret, sig_priv, kp, group_info, std::nullopt);
leaf_secret, sig_priv, kp, group_info, std::nullopt, { {}, encrypt, 0 });
auto commit_data = tls::marshal(commit);
auto state_id = store_state(std::move(state), request->encrypt_handshake());
auto state_id = store_state(std::move(state), encrypt);

response->set_state_id(state_id);
response->set_commit(bytes_to_string(commit_data));
Expand Down Expand Up @@ -564,7 +561,7 @@ MLSClientImpl::protect(CachedState& entry,
ProtectResponse* response)
{
auto pt = string_to_bytes(request->application_data());
auto ct = entry.state.protect(pt);
auto ct = entry.state.protect({}, pt, 0);
auto ct_data = tls::marshal(ct);
response->set_ciphertext(bytes_to_string(ct_data));
return Status::OK;
Expand All @@ -577,7 +574,11 @@ MLSClientImpl::unprotect(CachedState& entry,
{
auto ct_data = string_to_bytes(request->ciphertext());
auto ct = tls::get<mls::MLSCiphertext>(ct_data);
auto pt = entry.state.unprotect(ct);
auto [aad, pt] = entry.state.unprotect(ct);
mls::silence_unused(aad);

// TODO(RLB) We should update the gRPC spec so that it returns the AAD as well
// as the plaintext.
response->set_application_data(bytes_to_string(pt));
return Status::OK;
}
Expand All @@ -591,9 +592,9 @@ MLSClientImpl::add_proposal(CachedState& entry,
auto key_package_data = string_to_bytes(request->key_package());
auto key_package = tls::get<mls::KeyPackage>(key_package_data);

auto proposal = entry.state.add(key_package);
auto message = entry.state.add(key_package, entry.message_opts());

response->set_proposal(entry.marshal(proposal));
response->set_proposal(entry.marshal(message));
return Status::OK;
}

Expand All @@ -605,16 +606,18 @@ MLSClientImpl::commit(CachedState& entry,
// Unmarshal and handle external / by_reference proposals
const auto by_reference_size = request->by_reference_size();
for (int i = 0; i < by_reference_size; i++) {
auto pt = entry.unmarshal(request->by_reference(i));
auto should_be_null = entry.state.handle(pt);
auto msg = entry.unmarshal(request->by_reference(i));
auto should_be_null = entry.state.handle(msg);
if (should_be_null) {
throw std::runtime_error("Commit included among proposals");
}
}

auto inline_proposals = std::vector<mls::Proposal>(request->by_value_size());
auto inline_proposals = std::vector<mls::Proposal>();
#if 0
// TODO(#265): Re-enable
for (size_t i = 0; i < inline_proposals.size(); i++) {
auto pt = entry.unmarshal(request->by_value(i));
auto msg = entry.unmarshal(request->by_value(i));
if (pt.sender.sender != entry.state.index().val) {
return Status(grpc::INVALID_ARGUMENT,
"Inline proposal not from this member");
Expand All @@ -627,12 +630,14 @@ MLSClientImpl::commit(CachedState& entry,

inline_proposals[i] = std::move(*proposal);
}
#endif // 0

auto leaf_secret =
mls::random_bytes(entry.state.cipher_suite().secret_size());
auto [commit, welcome, next] = entry.state.commit(
leaf_secret,
mls::CommitOpts{ inline_proposals, true, entry.encrypt_handshake, {} });
mls::CommitOpts{ inline_proposals, true, entry.encrypt_handshake, {} },
entry.message_opts());

auto next_id = store_state(std::move(next), entry.encrypt_handshake);

Expand Down Expand Up @@ -667,8 +672,8 @@ MLSClientImpl::handle_commit(CachedState& entry,
// Handle the provided proposals, then the commit
const auto proposal_size = request->proposal_size();
for (int i = 0; i < proposal_size; i++) {
auto pt = entry.unmarshal(request->proposal(i));
auto should_be_null = entry.state.handle(pt);
auto msg = entry.unmarshal(request->proposal(i));
auto should_be_null = entry.state.handle(msg);
if (should_be_null) {
throw std::runtime_error("Commit included among proposals");
}
Expand All @@ -693,7 +698,7 @@ MLSClientImpl::handle_external_commit(
HandleExternalCommitResponse* response)
{
auto commit_data = string_to_bytes(request->commit());
auto commit = tls::get<mls::MLSPlaintext>(commit_data);
auto commit = tls::get<mls::MLSMessage>(commit_data);
auto should_be_next = entry.state.handle(commit);
if (!should_be_next) {
throw std::runtime_error("Commit failed to produce a new state");
Expand Down
5 changes: 3 additions & 2 deletions cmd/interop/src/mls_client_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,15 @@ class MLSClientImpl final : public MLSClient::Service
{
mls::State state;
bool encrypt_handshake;
mls::MessageOpts message_opts() const;

std::optional<std::string> pending_commit;
std::optional<uint32_t> pending_state_id;
void reset_pending();

// Marshal/unmarshal with encryption as required
std::string marshal(const mls::MLSPlaintext& pt);
mls::MLSPlaintext unmarshal(const std::string& wire);
std::string marshal(const mls::MLSMessage& msg);
mls::MLSMessage unmarshal(const std::string& wire);
};

std::map<uint32_t, CachedState> state_cache;
Expand Down
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
Loading