Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/openmls/openmls into openml…
Browse files Browse the repository at this point in the history
…s-main
  • Loading branch information
nplasterer committed Apr 26, 2024
2 parents 52cad0e + f7335a7 commit 0791f9d
Show file tree
Hide file tree
Showing 178 changed files with 7,847 additions and 4,201 deletions.
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

0 comments on commit 0791f9d

Please sign in to comment.