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

Upstream main into main #24

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
701dbef
Clippy fix for CI
raphaelrobert Apr 3, 2024
38106f5
Merge pull request #1540 from openmls/raphael/clippy-fix
raphaelrobert Apr 3, 2024
fe58308
Further improve credentials (#1539)
raphaelrobert Apr 3, 2024
a06f628
return leaf node for public staged commit states (#1541)
kkohbrok Apr 4, 2024
6ee540a
Introduce frankenstein framework (#1537)
raphaelrobert Apr 4, 2024
033f4e6
Remove cipher suite and version from Secret (#1545)
raphaelrobert Apr 4, 2024
182261c
Add experimental XWing-based PQ-secure ciphersuite (#1546)
kkohbrok Apr 5, 2024
8f76bd7
Remove CryptoConfig (#1548)
raphaelrobert Apr 5, 2024
24d68a5
build: bump peaceiris/actions-gh-pages from 3 to 4 (#1551)
dependabot[bot] Apr 8, 2024
639349a
build: bump peaceiris/actions-mdbook from 1 to 2 (#1552)
dependabot[bot] Apr 8, 2024
1ad514a
fixup build after #1548
franziskuskiefer Apr 9, 2024
7e11185
Disable MLS++ interop on CI (#1555)
kkohbrok Apr 9, 2024
9a1cafd
Merge branch 'main' into franziskus/fixup-build
franziskuskiefer Apr 9, 2024
fd76664
Merge pull request #1553 from openmls/franziskus/fixup-build
franziskuskiefer Apr 9, 2024
bdcd0c4
Enable handling of other/unknown proposals (#1542)
kkohbrok Apr 9, 2024
fc34dcc
Expose ext_sender_index function in `MlsGroup` (#1557)
kkohbrok Apr 9, 2024
dd7b9f1
expose propose_group_context_extensions and add a function (#1554)
franziskuskiefer Apr 9, 2024
b50f887
Some DS improvements (#1524)
kkohbrok Apr 10, 2024
820e84b
Remove `PartialEq` and `Clone` constraits for errors in traits (#1559)
kkohbrok Apr 10, 2024
00b0950
Add test for updating Unknown Group Context Extension (#1560)
cameronvoell Apr 12, 2024
e2cba32
Revert "Disable MLS++ interop on CI (#1555)"
kkohbrok Apr 16, 2024
f7335a7
New storage APIs (#1565)
franziskuskiefer Apr 26, 2024
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
15 changes: 15 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,18 @@ jobs:
- name: Build
if: ${{ matrix.arch != 'wasm32-unknown-unknown' }}
run: cargo build $TEST_MODE --verbose --target ${{ matrix.arch }} -p openmls

# Check feature powerset
check:
strategy:
fail-fast: false

runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: taiki-e/install-action@cargo-hack

- name: Cargo hack
run: cargo hack check --feature-powerset --no-dev-deps --verbose -p openmls
4 changes: 2 additions & 2 deletions .github/workflows/gh-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- name: Setup mdBook
uses: peaceiris/actions-mdbook@v1
uses: peaceiris/actions-mdbook@v2
with:
mdbook-version: 'latest'
- name: Build docs
Expand All @@ -43,7 +43,7 @@ jobs:
</html>
EOF
- name: Deploy docs to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: temp_docs
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [#1479](https://github.com/openmls/openmls/pull/1479): Allow the use of extensions with `ExtensionType::Unknown` in group context, key packages and leaf nodes
- [#1488](https://github.com/openmls/openmls/pull/1488): Allow unknown credentials. Credentials other than the basic credential or X.509 may be used now as long as they are encoded as variable-sized vectors.
- [#1527](https://github.com/openmls/openmls/pull/1527): CredentialType::Unknown is now called CredentialType::Other.
- [#1543](https://github.com/openmls/openmls/pull/1543): PreSharedKeyId.write_to_key_store() no longer requires the cipher suite.
- [#1546](https://github.com/openmls/openmls/pull/1546): Add experimental ciphersuite based on the PQ-secure XWing hybrid KEM (currently supported only by the libcrux crypto provider).
- [#1548](https://github.com/openmls/openmls/pull/1548): CryptoConfig is now replaced by just Ciphersuite.
- [#1542](https://github.com/openmls/openmls/pull/1542): Add support for custom proposals. ProposalType::Unknown is now called ProposalType::Other. Proposal::Unknown is now called Proposal::Other.
- [#1559](https://github.com/openmls/openmls/pull/1559): Remove the `PartialEq` type constraint on the error type of both the `OpenMlsRand` and `OpenMlsKeyStore` traits. Additionally, remove the `Clone` type constraint on the error type of the `OpenMlsRand` trait.

### Fixed

Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ members = [
"fuzz",
"cli",
"interop_client",
"memory_keystore",
"memory_storage",
"delivery-service/ds",
"delivery-service/ds-lib",
"basic_credential",
Expand Down
43 changes: 31 additions & 12 deletions basic_credential/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
use std::fmt::Debug;

use openmls_traits::{
key_store::{MlsEntity, MlsEntityId, OpenMlsKeyStore},
signatures::{Signer, SignerError},
storage::{self, StorageProvider, CURRENT_VERSION},
types::{CryptoError, SignatureScheme},
};

use p256::ecdsa::{signature::Signer as P256Signer, Signature, SigningKey};

use rand::rngs::OsRng;
use serde::{Deserialize, Serialize};
use tls_codec::{TlsDeserialize, TlsDeserializeBytes, TlsSerialize, TlsSize};

/// A signature key pair for the basic credential.
Expand Down Expand Up @@ -75,10 +76,6 @@ fn id(public_key: &[u8], signature_scheme: SignatureScheme) -> Vec<u8> {
id
}

impl MlsEntity for SignatureKeyPair {
const ID: MlsEntityId = MlsEntityId::SignatureKeyPair;
}

impl SignatureKeyPair {
/// Generates a fresh signature keypair using the [`SignatureScheme`].
pub fn new(signature_scheme: SignatureScheme) -> Result<Self, CryptoError> {
Expand Down Expand Up @@ -112,25 +109,32 @@ impl SignatureKeyPair {
}
}

fn id(&self) -> Vec<u8> {
id(&self.public, self.signature_scheme)
fn id(&self) -> StorageId {
StorageId {
value: id(&self.public, self.signature_scheme),
}
}

/// Store this signature key pair in the key store.
pub fn store<T>(&self, key_store: &T) -> Result<(), <T as OpenMlsKeyStore>::Error>
pub fn store<T>(&self, store: &T) -> Result<(), T::Error>
where
T: OpenMlsKeyStore,
T: StorageProvider<CURRENT_VERSION>,
{
key_store.store(&self.id(), self)
store.write_signature_key_pair(&self.id(), self)
}

/// Read a signature key pair from the key store.
pub fn read(
key_store: &impl OpenMlsKeyStore,
store: &impl StorageProvider<CURRENT_VERSION>,
public_key: &[u8],
signature_scheme: SignatureScheme,
) -> Option<Self> {
key_store.read(&id(public_key, signature_scheme))
store
.signature_key_pair(&StorageId {
value: id(public_key, signature_scheme),
})
.ok()
.flatten()
}

/// Get the public key as byte slice.
Expand All @@ -153,3 +157,18 @@ impl SignatureKeyPair {
&self.private
}
}

// Storage

#[derive(Debug, Serialize, Deserialize)]
struct StorageId {
value: Vec<u8>,
}

// Implement key traits for the storage id
impl storage::Key<CURRENT_VERSION> for StorageId {}
impl storage::traits::SignaturePublicKey<CURRENT_VERSION> for StorageId {}

// Implement entity trait for the signature key pair
impl storage::Entity<CURRENT_VERSION> for SignatureKeyPair {}
impl storage::traits::SignatureKeyPair<CURRENT_VERSION> for SignatureKeyPair {}
1 change: 1 addition & 0 deletions book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- [Removing members from a group](user_manual/remove_members.md)
- [Updating own key package](user_manual/updates.md)
- [Leaving a group](user_manual/leaving.md)
- [Custom proposals](user_manual/custom_proposals.md)
- [Creating application messages](user_manual/application_messages.md)
- [Committing to pending proposals](user_manual/commit_to_proposals.md)
- [Processing incoming messages](user_manual/processing.md)
Expand Down
1 change: 1 addition & 0 deletions book/src/message_validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ The following is a list of the individual semantic validation steps performed by
| `ValSem110` | Update Proposal: Encryption key must be unique among proposals & members | ✅ | ✅ | `openmls/src/group/tests/test_proposal_validation.rs` |
| `ValSem111` | Update Proposal: The sender of a full Commit must not include own update proposals | ✅ | ✅ | `openmls/src/group/tests/test_proposal_validation.rs` |
| `ValSem112` | Update Proposal: The sender of a standalone update proposal must be of type member | ✅ | ✅ | `openmls/src/group/tests/test_proposal_validation.rs` |
| `ValSem113` | All Proposals: The proposal type must be supported by all members of the group | ✅ | ✅ | `openmls/src/group/tests/test_proposal_validation.rs` |

### Commit message validation

Expand Down
15 changes: 15 additions & 0 deletions book/src/user_manual/custom_proposals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Custom proposals

OpenMLS allows the creation and use of application-defined proposals. To create such a proposal, the application needs to define a Proposal Type in such a way that its value doesn't collide with any Proposal Types defined in Section 17.4. of RFC 9420. If the proposal is meant to be used only inside of a particular application, the value of the Proposal Type is recommended to be in the range between `0xF000` and `0xFFFF`, as that range is reserved for private use.

Custom proposals can contain arbitrary octet-strings as defined by the application. Any policy decisions based on custom proposals will have to be made by the application, such as the decision to include a given custom proposal in a commit, or whether to accept a commit that includes one or more custom proposals. To decide the latter, applications can inspect the queued proposals in a `ProcessedMessageContent::StagedCommitMesage(staged_commit)`.

Example on how to use custom proposals:

```rust,no_run,noplayground
{{#include ../../../openmls/tests/book_code.rs:custom_proposal_type}}
```

```rust,no_run,noplayground
{{#include ../../../openmls/tests/book_code.rs:custom_proposal_usage}}
```
4 changes: 3 additions & 1 deletion cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ openmls = { path = "../openmls", features = ["test-utils"] }
ds-lib = { path = "../delivery-service/ds-lib" }
openmls_traits = { path = "../traits" }
openmls_rust_crypto = { path = "../openmls_rust_crypto" }
openmls_memory_keystore = { path = "../memory_keystore" }
openmls_memory_storage = { path = "../memory_storage", features = [
"persistence",
] }
openmls_basic_credential = { path = "../basic_credential" }
serde = { version = "^1.0" }
thiserror = "1.0"
Expand Down
58 changes: 44 additions & 14 deletions cli/src/backend.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
use tls_codec::{Deserialize, TlsVecU16, TlsVecU32};
use url::Url;

use crate::networking::get_with_body;

use super::{
networking::{get, post},
user::User,
};

use ds_lib::*;
use ds_lib::{
messages::{
AuthToken, PublishKeyPackagesRequest, RecvMessageRequest, RegisterClientRequest,
RegisterClientSuccessResponse,
},
*,
};
use openmls::prelude::*;

pub struct Backend {
Expand All @@ -15,30 +23,37 @@ pub struct Backend {

impl Backend {
/// Register a new client with the server.
pub fn register_client(&self, user: &User) -> Result<String, String> {
pub fn register_client(
&self,
key_packages: Vec<(Vec<u8>, KeyPackage)>,
) -> Result<AuthToken, String> {
let mut url = self.ds_url.clone();
url.set_path("/clients/register");

let client_info = ClientInfo::new(
user.username.clone(),
user.key_packages()
let key_packages = ClientKeyPackages(
key_packages
.into_iter()
.map(|(b, kp)| (b, KeyPackageIn::from(kp)))
.collect(),
.map(|(b, kp)| (b.into(), KeyPackageIn::from(kp)))
.collect::<Vec<_>>()
.into(),
);
let response = post(&url, &client_info)?;
let request = RegisterClientRequest { key_packages };
let response_bytes = post(&url, &request)?;
let response =
RegisterClientSuccessResponse::tls_deserialize(&mut response_bytes.as_slice())
.map_err(|e| format!("Error decoding server response: {e:?}"))?;

Ok(String::from_utf8(response).unwrap())
Ok(response.auth_token)
}

/// Get a list of all clients with name, ID, and key packages from the
/// server.
pub fn list_clients(&self) -> Result<Vec<ClientInfo>, String> {
pub fn list_clients(&self) -> Result<Vec<Vec<u8>>, String> {
let mut url = self.ds_url.clone();
url.set_path("/clients/list");

let response = get(&url)?;
match TlsVecU32::<ClientInfo>::tls_deserialize(&mut response.as_slice()) {
match TlsVecU32::<Vec<u8>>::tls_deserialize(&mut response.as_slice()) {
Ok(clients) => Ok(clients.into()),
Err(e) => Err(format!("Error decoding server response: {e:?}")),
}
Expand All @@ -59,14 +74,22 @@ impl Backend {
}

/// Publish client additional key packages
pub fn publish_key_packages(&self, user: &User, ckp: &ClientKeyPackages) -> Result<(), String> {
pub fn publish_key_packages(&self, user: &User, ckp: ClientKeyPackages) -> Result<(), String> {
let Some(auth_token) = user.auth_token() else {
return Err("Please register user before publishing key packages".to_string());
};
let mut url = self.ds_url.clone();
let path = "/clients/key_packages/".to_string()
+ &base64::encode_config(user.identity.borrow().identity(), base64::URL_SAFE);
url.set_path(&path);

let request = PublishKeyPackagesRequest {
key_packages: ckp,
auth_token: auth_token.clone(),
};

// The response should be empty.
let _response = post(&url, &ckp)?;
let _response = post(&url, &request)?;
Ok(())
}

Expand All @@ -92,12 +115,19 @@ impl Backend {

/// Get a list of all new messages for the user.
pub fn recv_msgs(&self, user: &User) -> Result<Vec<MlsMessageIn>, String> {
let Some(auth_token) = user.auth_token() else {
return Err("Please register user before publishing key packages".to_string());
};
let mut url = self.ds_url.clone();
let path = "/recv/".to_string()
+ &base64::encode_config(user.identity.borrow().identity(), base64::URL_SAFE);
url.set_path(&path);

let response = get(&url)?;
let request = RecvMessageRequest {
auth_token: auth_token.clone(),
};

let response = get_with_body(&url, &request)?;
match TlsVecU16::<MlsMessageIn>::tls_deserialize(&mut response.as_slice()) {
Ok(r) => Ok(r.into()),
Err(e) => Err(format!("Invalid message list: {e:?}")),
Expand Down
6 changes: 0 additions & 6 deletions cli/src/file_helpers.rs

This file was deleted.

33 changes: 18 additions & 15 deletions cli/src/identity.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::collections::HashMap;

use openmls::prelude::{config::CryptoConfig, *};
use openmls::prelude::*;
use openmls_basic_credential::SignatureKeyPair;
use openmls_traits::OpenMlsProvider;

Expand All @@ -21,22 +21,19 @@ impl Identity {
pub(crate) fn new(
ciphersuite: Ciphersuite,
crypto: &OpenMlsRustPersistentCrypto,
id: &[u8],
username: &[u8],
) -> Self {
let credential = BasicCredential::new(id.to_vec()).unwrap();
let credential = BasicCredential::new(username.to_vec());
let signature_keys = SignatureKeyPair::new(ciphersuite.signature_algorithm()).unwrap();
let credential_with_key = CredentialWithKey {
credential: credential.into(),
signature_key: signature_keys.to_public_vec().into(),
};
signature_keys.store(crypto.key_store()).unwrap();
signature_keys.store(crypto.storage()).unwrap();

let key_package = KeyPackage::builder()
.build(
CryptoConfig {
ciphersuite,
version: ProtocolVersion::default(),
},
ciphersuite,
crypto,
&signature_keys,
credential_with_key.clone(),
Expand All @@ -46,11 +43,12 @@ impl Identity {
Self {
kp: HashMap::from([(
key_package
.key_package()
.hash_ref(crypto.crypto())
.unwrap()
.as_slice()
.to_vec(),
key_package,
key_package.key_package().clone(),
)]),
credential_with_key,
signer: signature_keys,
Expand All @@ -65,10 +63,7 @@ impl Identity {
) -> KeyPackage {
let key_package = KeyPackage::builder()
.build(
CryptoConfig {
ciphersuite,
version: ProtocolVersion::default(),
},
ciphersuite,
crypto,
&self.signer,
self.credential_with_key.clone(),
Expand All @@ -77,17 +72,25 @@ impl Identity {

self.kp.insert(
key_package
.key_package()
.hash_ref(crypto.crypto())
.unwrap()
.as_slice()
.to_vec(),
key_package.clone(),
key_package.key_package().clone(),
);
key_package
key_package.key_package().clone()
}

/// Get the plain identity as byte vector.
pub fn identity(&self) -> &[u8] {
self.credential_with_key.credential.serialized_content()
}

/// Get the plain identity as byte vector.
pub fn identity_as_string(&self) -> String {
std::str::from_utf8(self.credential_with_key.credential.serialized_content())
.unwrap()
.to_string()
}
}
Loading
Loading